linux-s390.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 00/52] s390 patches for the next merge window (2.6.33)
@ 2009-11-13 15:08 Martin Schwidefsky
  2009-11-13 15:08 ` [patch 01/52] [PATCH] Improve address space check Martin Schwidefsky
                   ` (52 more replies)
  0 siblings, 53 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens

Greetings,
the current patch queue on git390 for the next merge window.
52 patches, over half of them (27) are for the common-io-layer
rework. 6 patches for the optimization of the fault handler,
another 6 for the new cex3 crypto cards and some other stuff.
As always, have fun ..

-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 01/52] [PATCH] Improve address space check.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 02/52] [PATCH] Improve address space mode selection Martin Schwidefsky
                   ` (51 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 100-mm-check-space.diff --]
[-- Type: text/plain, Size: 8146 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

A data access in access-register mode always is a user mode access,
the code to inspect the access-registers can be removed. The second
change is to use a different test to check for no-execute fault.
The third change is to pass the translation exception identification
as parameter, in theory the trans_exc_code in the lowcore could have
been overwritten by the time the call to check_space from do_no_context
is done.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/mm/fault.c |   99 +++++++++++++++++++++++----------------------------
 1 file changed, 45 insertions(+), 54 deletions(-)

Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
@@ -100,39 +100,28 @@
 
 /*
  * Returns the address space associated with the fault.
- * Returns 0 for kernel space, 1 for user space and
- * 2 for code execution in user space with noexec=on.
+ * Returns 0 for kernel space and 1 for user space.
  */
-static inline int check_space(struct task_struct *tsk)
+static inline int user_space_fault(unsigned long trans_exc_code)
 {
 	/*
-	 * The lowest two bits of S390_lowcore.trans_exc_code
-	 * indicate which paging table was used.
+	 * The lowest two bits of the translation exception
+	 * identification indicate which paging table was used.
 	 */
-	int desc = S390_lowcore.trans_exc_code & 3;
-
-	if (desc == 3)	/* Home Segment Table Descriptor */
-		return switch_amode == 0;
-	if (desc == 2)	/* Secondary Segment Table Descriptor */
-		return tsk->thread.mm_segment.ar4;
-#ifdef CONFIG_S390_SWITCH_AMODE
-	if (unlikely(desc == 1)) { /* STD determined via access register */
-		/* %a0 always indicates primary space. */
-		if (S390_lowcore.exc_access_id != 0) {
-			save_access_regs(tsk->thread.acrs);
-			/*
-			 * An alet of 0 indicates primary space.
-			 * An alet of 1 indicates secondary space.
-			 * Any other alet values generate an
-			 * alen-translation exception.
-			 */
-			if (tsk->thread.acrs[S390_lowcore.exc_access_id])
-				return tsk->thread.mm_segment.ar4;
-		}
-	}
-#endif
-	/* Primary Segment Table Descriptor */
-	return switch_amode << s390_noexec;
+	trans_exc_code &= 3;
+	if (trans_exc_code == 2)
+		/* Access via secondary space, set_fs setting decides */
+		return current->thread.mm_segment.ar4;
+	if (!switch_amode)
+		/* User space if the access has been done via home space. */
+		return trans_exc_code == 3;
+	/*
+	 * If the user space is not the home space the kernel runs in home
+	 * space. Access via secondary space has already been covered,
+	 * access via primary space or access register is from user space
+	 * and access via home space is from the kernel.
+	 */
+	return trans_exc_code != 3;
 }
 
 /*
@@ -162,9 +151,10 @@
 }
 
 static void do_no_context(struct pt_regs *regs, unsigned long error_code,
-			  unsigned long address)
+			  unsigned long trans_exc_code)
 {
 	const struct exception_table_entry *fixup;
+	unsigned long address;
 
 	/* Are we prepared to handle this kernel fault?  */
 	fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
@@ -177,7 +167,8 @@
 	 * Oops. The kernel tried to access some bad page. We'll have to
 	 * terminate things with extreme prejudice.
 	 */
-	if (check_space(current) == 0)
+	address = trans_exc_code & __FAIL_ADDR_MASK;
+	if (user_space_fault(trans_exc_code) == 0)
 		printk(KERN_ALERT "Unable to handle kernel pointer dereference"
 		       " at virtual kernel address %p\n", (void *)address);
 	else
@@ -188,7 +179,8 @@
 	do_exit(SIGKILL);
 }
 
-static void do_low_address(struct pt_regs *regs, unsigned long error_code)
+static void do_low_address(struct pt_regs *regs, unsigned long error_code,
+			   unsigned long trans_exc_code)
 {
 	/* Low-address protection hit in kernel mode means
 	   NULL pointer write access in kernel mode.  */
@@ -198,11 +190,11 @@
 		do_exit(SIGKILL);
 	}
 
-	do_no_context(regs, error_code, 0);
+	do_no_context(regs, error_code, trans_exc_code);
 }
 
 static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
-		      unsigned long address)
+		      unsigned long trans_exc_code)
 {
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
@@ -212,13 +204,13 @@
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	tsk->thread.prot_addr = address;
+	tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
 	tsk->thread.trap_no = error_code;
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
 	if (!(regs->psw.mask & PSW_MASK_PSTATE))
-		do_no_context(regs, error_code, address);
+		do_no_context(regs, error_code, trans_exc_code);
 }
 
 #ifdef CONFIG_S390_EXEC_PROTECT
@@ -272,13 +264,13 @@
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
 static inline void
-do_exception(struct pt_regs *regs, unsigned long error_code, int write)
+do_exception(struct pt_regs *regs, unsigned long error_code, int write,
+	     unsigned long trans_exc_code)
 {
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	struct vm_area_struct *vma;
 	unsigned long address;
-	int space;
 	int si_code;
 	int fault;
 
@@ -288,18 +280,15 @@
 	tsk = current;
 	mm = tsk->mm;
 
-	/* get the failing address and the affected space */
-	address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
-	space = check_space(tsk);
-
 	/*
 	 * Verify that the fault happened in user space, that
 	 * we are not in an interrupt and that there is a 
 	 * user context.
 	 */
-	if (unlikely(space == 0 || in_atomic() || !mm))
+	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
 		goto no_context;
 
+	address = trans_exc_code & __FAIL_ADDR_MASK;
 	/*
 	 * When we get here, the fault happened in the current
 	 * task's user address space, so we can switch on the
@@ -315,7 +304,8 @@
 		goto bad_area;
 
 #ifdef CONFIG_S390_EXEC_PROTECT
-	if (unlikely((space == 2) && !(vma->vm_flags & VM_EXEC)))
+	if (unlikely((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+		     (trans_exc_code & 3) == 0 && !(vma->vm_flags & VM_EXEC)))
 		if (!signal_return(mm, regs, address, error_code))
 			/*
 			 * signal_return() has done an up_read(&mm->mmap_sem)
@@ -397,12 +387,14 @@
 	}
 
 no_context:
-	do_no_context(regs, error_code, address);
+	do_no_context(regs, error_code, trans_exc_code);
 }
 
 void __kprobes do_protection_exception(struct pt_regs *regs,
 				       long error_code)
 {
+	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+
 	/* Protection exception is supressing, decrement psw address. */
 	regs->psw.addr -= (error_code >> 16);
 	/*
@@ -410,31 +402,30 @@
 	 * as a special case because the translation exception code
 	 * field is not guaranteed to contain valid data in this case.
 	 */
-	if (unlikely(!(S390_lowcore.trans_exc_code & 4))) {
-		do_low_address(regs, error_code);
+	if (unlikely(!(trans_exc_code & 4))) {
+		do_low_address(regs, error_code, trans_exc_code);
 		return;
 	}
-	do_exception(regs, 4, 1);
+	do_exception(regs, 4, 1, trans_exc_code);
 }
 
 void __kprobes do_dat_exception(struct pt_regs *regs, long error_code)
 {
-	do_exception(regs, error_code & 0xff, 0);
+	do_exception(regs, error_code & 0xff, 0, S390_lowcore.trans_exc_code);
 }
 
 #ifdef CONFIG_64BIT
 void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
 {
+	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
 	struct mm_struct *mm;
 	struct vm_area_struct *vma;
 	unsigned long address;
-	int space;
 
 	mm = current->mm;
-	address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
-	space = check_space(current);
+	address = trans_exc_code & __FAIL_ADDR_MASK;
 
-	if (unlikely(space == 0 || in_atomic() || !mm))
+	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
 		goto no_context;
 
 	local_irq_enable();
@@ -457,7 +448,7 @@
 	}
 
 no_context:
-	do_no_context(regs, error_code, address);
+	do_no_context(regs, error_code, trans_exc_code);
 }
 #endif
 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 02/52] [PATCH] Improve address space mode selection.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
  2009-11-13 15:08 ` [patch 01/52] [PATCH] Improve address space check Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 03/52] [PATCH] Improve notify_page_fault implementation Martin Schwidefsky
                   ` (50 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 101-mm-user-mode.diff --]
[-- Type: text/plain, Size: 12057 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Introduce user_mode to replace the two variables switch_amode and
s390_noexec. There are three valid combinations of the old values:
  1) switch_amode == 0 && s390_noexec == 0
  2) switch_amode == 1 && s390_noexec == 0
  3) switch_amode == 1 && s390_noexec == 1
They get replaced by
  1) user_mode == HOME_SPACE_MODE
  2) user_mode == PRIMARY_SPACE_MODE
  3) user_mode == SECONDARY_SPACE_MODE
The new kernel parameter user_mode=[primary,secondary,home] lets
you choose the address space mode the user space processes should
use. In addition the CONFIG_S390_SWITCH_AMODE config option
is removed.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/Kconfig                   |   15 ---------------
 arch/s390/defconfig                 |    1 -
 arch/s390/include/asm/mmu_context.h |    4 ++--
 arch/s390/include/asm/pgalloc.h     |    3 ++-
 arch/s390/include/asm/setup.h       |   17 ++++++-----------
 arch/s390/kernel/setup.c            |   36 ++++++++++++++++++++----------------
 arch/s390/kernel/vdso.c             |    9 +++++----
 arch/s390/kvm/Kconfig               |    1 -
 arch/s390/lib/uaccess_mvcos.c       |    4 ----
 arch/s390/mm/fault.c                |    4 ++--
 arch/s390/mm/pgtable.c              |    2 +-
 11 files changed, 38 insertions(+), 58 deletions(-)

Index: quilt-2.6/arch/s390/defconfig
===================================================================
--- quilt-2.6.orig/arch/s390/defconfig	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/defconfig	2009-11-13 16:08:12.000000000 +0100
@@ -185,7 +185,6 @@
 CONFIG_COMPAT=y
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_AUDIT_ARCH=y
-CONFIG_S390_SWITCH_AMODE=y
 CONFIG_S390_EXEC_PROTECT=y
 
 #
Index: quilt-2.6/arch/s390/include/asm/mmu_context.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/mmu_context.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/mmu_context.h	2009-11-13 16:08:12.000000000 +0100
@@ -36,7 +36,7 @@
 		mm->context.has_pgste = 1;
 		mm->context.alloc_pgste = 1;
 	} else {
-		mm->context.noexec = s390_noexec;
+		mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
 		mm->context.has_pgste = 0;
 		mm->context.alloc_pgste = 0;
 	}
@@ -58,7 +58,7 @@
 	pgd_t *pgd = mm->pgd;
 
 	S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
-	if (switch_amode) {
+	if (user_mode != HOME_SPACE_MODE) {
 		/* Load primary space page table origin. */
 		pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
 		S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
Index: quilt-2.6/arch/s390/include/asm/pgalloc.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/pgalloc.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/pgalloc.h	2009-11-13 16:08:12.000000000 +0100
@@ -143,7 +143,8 @@
 	spin_lock_init(&mm->context.list_lock);
 	INIT_LIST_HEAD(&mm->context.crst_list);
 	INIT_LIST_HEAD(&mm->context.pgtable_list);
-	return (pgd_t *) crst_table_alloc(mm, s390_noexec);
+	return (pgd_t *)
+		crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
 }
 #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
 
Index: quilt-2.6/arch/s390/include/asm/setup.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/setup.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/setup.h	2009-11-13 16:08:12.000000000 +0100
@@ -49,17 +49,12 @@
 
 void detect_memory_layout(struct mem_chunk chunk[]);
 
-#ifdef CONFIG_S390_SWITCH_AMODE
-extern unsigned int switch_amode;
-#else
-#define switch_amode	(0)
-#endif
-
-#ifdef CONFIG_S390_EXEC_PROTECT
-extern unsigned int s390_noexec;
-#else
-#define s390_noexec	(0)
-#endif
+#define PRIMARY_SPACE_MODE	0
+#define ACCESS_REGISTER_MODE	1
+#define SECONDARY_SPACE_MODE	2
+#define HOME_SPACE_MODE		3
+
+extern unsigned int user_mode;
 
 /*
  * Machine features detected in head.S
Index: quilt-2.6/arch/s390/Kconfig
===================================================================
--- quilt-2.6.orig/arch/s390/Kconfig	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/Kconfig	2009-11-13 16:08:12.000000000 +0100
@@ -192,23 +192,8 @@
 	bool
 	default y
 
-config S390_SWITCH_AMODE
-	bool "Switch kernel/user addressing modes"
-	help
-	  This option allows to switch the addressing modes of kernel and user
-	  space. The kernel parameter switch_amode=on will enable this feature,
-	  default is disabled. Enabling this (via kernel parameter) on machines
-	  earlier than IBM System z9-109 EC/BC will reduce system performance.
-
-	  Note that this option will also be selected by selecting the execute
-	  protection option below. Enabling the execute protection via the
-	  noexec kernel parameter will also switch the addressing modes,
-	  independent of the switch_amode kernel parameter.
-
-
 config S390_EXEC_PROTECT
 	bool "Data execute protection"
-	select S390_SWITCH_AMODE
 	help
 	  This option allows to enable a buffer overflow protection for user
 	  space programs and it also selects the addressing mode option above.
Index: quilt-2.6/arch/s390/kernel/setup.c
===================================================================
--- quilt-2.6.orig/arch/s390/kernel/setup.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/kernel/setup.c	2009-11-13 16:08:12.000000000 +0100
@@ -305,9 +305,8 @@
 }
 early_param("mem", early_parse_mem);
 
-#ifdef CONFIG_S390_SWITCH_AMODE
-unsigned int switch_amode = 0;
-EXPORT_SYMBOL_GPL(switch_amode);
+unsigned int user_mode = HOME_SPACE_MODE;
+EXPORT_SYMBOL_GPL(user_mode);
 
 static int set_amode_and_uaccess(unsigned long user_amode,
 				 unsigned long user32_amode)
@@ -340,23 +339,29 @@
  */
 static int __init early_parse_switch_amode(char *p)
 {
-	switch_amode = 1;
+	if (user_mode != SECONDARY_SPACE_MODE)
+		user_mode = PRIMARY_SPACE_MODE;
 	return 0;
 }
 early_param("switch_amode", early_parse_switch_amode);
 
-#else /* CONFIG_S390_SWITCH_AMODE */
-static inline int set_amode_and_uaccess(unsigned long user_amode,
-					unsigned long user32_amode)
+static int __init early_parse_user_mode(char *p)
 {
+	if (p && strcmp(p, "primary") == 0)
+		user_mode = PRIMARY_SPACE_MODE;
+#ifdef CONFIG_S390_EXEC_PROTECT
+	else if (p && strcmp(p, "secondary") == 0)
+		user_mode = SECONDARY_SPACE_MODE;
+#endif
+	else if (!p || strcmp(p, "home") == 0)
+		user_mode = HOME_SPACE_MODE;
+	else
+		return 1;
 	return 0;
 }
-#endif /* CONFIG_S390_SWITCH_AMODE */
+early_param("user_mode", early_parse_user_mode);
 
 #ifdef CONFIG_S390_EXEC_PROTECT
-unsigned int s390_noexec = 0;
-EXPORT_SYMBOL_GPL(s390_noexec);
-
 /*
  * Enable execute protection?
  */
@@ -364,8 +369,7 @@
 {
 	if (!strncmp(p, "off", 3))
 		return 0;
-	switch_amode = 1;
-	s390_noexec = 1;
+	user_mode = SECONDARY_SPACE_MODE;
 	return 0;
 }
 early_param("noexec", early_parse_noexec);
@@ -373,7 +377,7 @@
 
 static void setup_addressing_mode(void)
 {
-	if (s390_noexec) {
+	if (user_mode == SECONDARY_SPACE_MODE) {
 		if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
 					  PSW32_ASC_SECONDARY))
 			pr_info("Execute protection active, "
@@ -381,7 +385,7 @@
 		else
 			pr_info("Execute protection active, "
 				"mvcos not available\n");
-	} else if (switch_amode) {
+	} else if (user_mode == PRIMARY_SPACE_MODE) {
 		if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
 			pr_info("Address spaces switched, "
 				"mvcos available\n");
@@ -411,7 +415,7 @@
 	lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
 	lc->restart_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
-	if (switch_amode)
+	if (user_mode != HOME_SPACE_MODE)
 		lc->restart_psw.mask |= PSW_ASC_HOME;
 	lc->external_new_psw.mask = psw_kernel_bits;
 	lc->external_new_psw.addr =
Index: quilt-2.6/arch/s390/kernel/vdso.c
===================================================================
--- quilt-2.6.orig/arch/s390/kernel/vdso.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/kernel/vdso.c	2009-11-13 16:08:12.000000000 +0100
@@ -86,7 +86,8 @@
 	unsigned int facility_list;
 
 	facility_list = stfl();
-	vd->ectg_available = switch_amode && (facility_list & 1);
+	vd->ectg_available =
+		user_mode != HOME_SPACE_MODE && (facility_list & 1);
 }
 
 #ifdef CONFIG_64BIT
@@ -114,7 +115,7 @@
 
 	lowcore->vdso_per_cpu_data = __LC_PASTE;
 
-	if (!switch_amode || !vdso_enabled)
+	if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
 		return 0;
 
 	segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
@@ -160,7 +161,7 @@
 	unsigned long segment_table, page_table, page_frame;
 	u32 *psal, *aste;
 
-	if (!switch_amode || !vdso_enabled)
+	if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
 		return;
 
 	psal = (u32 *)(addr_t) lowcore->paste[4];
@@ -184,7 +185,7 @@
 
 static void vdso_init_cr5(void)
 {
-	if (switch_amode && vdso_enabled)
+	if (user_mode != HOME_SPACE_MODE && vdso_enabled)
 		on_each_cpu(__vdso_init_cr5, NULL, 1);
 }
 #endif /* CONFIG_64BIT */
Index: quilt-2.6/arch/s390/kvm/Kconfig
===================================================================
--- quilt-2.6.orig/arch/s390/kvm/Kconfig	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/kvm/Kconfig	2009-11-13 16:08:12.000000000 +0100
@@ -20,7 +20,6 @@
 	depends on HAVE_KVM && EXPERIMENTAL
 	select PREEMPT_NOTIFIERS
 	select ANON_INODES
-	select S390_SWITCH_AMODE
 	---help---
 	  Support hosting paravirtualized guest machines using the SIE
 	  virtualization capability on the mainframe. This should work
Index: quilt-2.6/arch/s390/lib/uaccess_mvcos.c
===================================================================
--- quilt-2.6.orig/arch/s390/lib/uaccess_mvcos.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/lib/uaccess_mvcos.c	2009-11-13 16:08:12.000000000 +0100
@@ -162,7 +162,6 @@
 	return size;
 }
 
-#ifdef CONFIG_S390_SWITCH_AMODE
 static size_t strnlen_user_mvcos(size_t count, const char __user *src)
 {
 	char buf[256];
@@ -200,7 +199,6 @@
 	} while ((len_str == len) && (done < count));
 	return done;
 }
-#endif /* CONFIG_S390_SWITCH_AMODE */
 
 struct uaccess_ops uaccess_mvcos = {
 	.copy_from_user = copy_from_user_mvcos_check,
@@ -215,7 +213,6 @@
 	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
 };
 
-#ifdef CONFIG_S390_SWITCH_AMODE
 struct uaccess_ops uaccess_mvcos_switch = {
 	.copy_from_user = copy_from_user_mvcos,
 	.copy_from_user_small = copy_from_user_mvcos,
@@ -228,4 +225,3 @@
 	.futex_atomic_op = futex_atomic_op_pt,
 	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
 };
-#endif
Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
+++ quilt-2.6/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
@@ -112,7 +112,7 @@
 	if (trans_exc_code == 2)
 		/* Access via secondary space, set_fs setting decides */
 		return current->thread.mm_segment.ar4;
-	if (!switch_amode)
+	if (user_mode == HOME_SPACE_MODE)
 		/* User space if the access has been done via home space. */
 		return trans_exc_code == 3;
 	/*
@@ -168,7 +168,7 @@
 	 * terminate things with extreme prejudice.
 	 */
 	address = trans_exc_code & __FAIL_ADDR_MASK;
-	if (user_space_fault(trans_exc_code) == 0)
+	if (!user_space_fault(trans_exc_code))
 		printk(KERN_ALERT "Unable to handle kernel pointer dereference"
 		       " at virtual kernel address %p\n", (void *)address);
 	else
Index: quilt-2.6/arch/s390/mm/pgtable.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/pgtable.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/mm/pgtable.c	2009-11-13 16:08:12.000000000 +0100
@@ -269,7 +269,7 @@
 	struct mm_struct *mm, *old_mm;
 
 	/* Do we have switched amode? If no, we cannot do sie */
-	if (!switch_amode)
+	if (user_mode == HOME_SPACE_MODE)
 		return -EINVAL;
 
 	/* Do we have pgstes? if yes, we are done */

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 03/52] [PATCH] Improve notify_page_fault implementation.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
  2009-11-13 15:08 ` [patch 01/52] [PATCH] Improve address space check Martin Schwidefsky
  2009-11-13 15:08 ` [patch 02/52] [PATCH] Improve address space mode selection Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 04/52] [PATCH] fault handler performance optimization Martin Schwidefsky
                   ` (49 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 102-mm-kprobe-notify.diff --]
[-- Type: text/plain, Size: 1446 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

notify_page_fault does a preempt_disable/preempt_enable for each
fault generated by a kernel access to user space. If kprobes
is not active that is unnecessary since the interrupts are not
reenabled yet. To play safe repeat the kprobe_running check after
preempt_disable().

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/mm/fault.c |   14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
+++ quilt-2.6/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
@@ -52,11 +52,11 @@
 extern int sysctl_userprocess_debug;
 #endif
 
-#ifdef CONFIG_KPROBES
-static inline int notify_page_fault(struct pt_regs *regs, long err)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
 	int ret = 0;
 
+#ifdef CONFIG_KPROBES
 	/* kprobe_running() needs smp_processor_id() */
 	if (!user_mode(regs)) {
 		preempt_disable();
@@ -64,15 +64,9 @@
 			ret = 1;
 		preempt_enable();
 	}
-
+#endif
 	return ret;
 }
-#else
-static inline int notify_page_fault(struct pt_regs *regs, long err)
-{
-	return 0;
-}
-#endif
 
 
 /*
@@ -274,7 +268,7 @@
 	int si_code;
 	int fault;
 
-	if (notify_page_fault(regs, error_code))
+	if (notify_page_fault(regs))
 		return;
 
 	tsk = current;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 04/52] [PATCH] fault handler performance optimization.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (2 preceding siblings ...)
  2009-11-13 15:08 ` [patch 03/52] [PATCH] Improve notify_page_fault implementation Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 05/52] [PATCH] fault handler access flags check Martin Schwidefsky
                   ` (48 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 103-mm-fault-error.diff --]
[-- Type: text/plain, Size: 14180 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Slim down the do_exception function to handle only the fast path of a
fault and move the exceptional cases into a new function. That slightly
increases the performance of the fault handling.

Build fix for !CONFIG_COMPAT by
Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/mm/fault.c |  258 +++++++++++++++++++++++++--------------------------
 1 file changed, 129 insertions(+), 129 deletions(-)

Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
+++ quilt-2.6/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
@@ -34,16 +34,15 @@
 #include <asm/pgtable.h>
 #include <asm/s390_ext.h>
 #include <asm/mmu_context.h>
+#include <asm/compat.h>
 #include "../kernel/entry.h"
 
 #ifndef CONFIG_64BIT
 #define __FAIL_ADDR_MASK 0x7ffff000
-#define __FIXUP_MASK 0x7fffffff
 #define __SUBCODE_MASK 0x0200
 #define __PF_RES_FIELD 0ULL
 #else /* CONFIG_64BIT */
 #define __FAIL_ADDR_MASK -4096L
-#define __FIXUP_MASK ~0L
 #define __SUBCODE_MASK 0x0600
 #define __PF_RES_FIELD 0x8000000000000000ULL
 #endif /* CONFIG_64BIT */
@@ -52,6 +51,10 @@
 extern int sysctl_userprocess_debug;
 #endif
 
+#define VM_FAULT_BADCONTEXT	0x010000
+#define VM_FAULT_BADMAP		0x020000
+#define VM_FAULT_BADACCESS	0x040000
+
 static inline int notify_page_fault(struct pt_regs *regs)
 {
 	int ret = 0;
@@ -122,18 +125,22 @@
  * Send SIGSEGV to task.  This is an external routine
  * to keep the stack usage of do_page_fault small.
  */
-static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
-		       int si_code, unsigned long address)
+static noinline void do_sigsegv(struct pt_regs *regs, long int_code,
+				int si_code, unsigned long trans_exc_code)
 {
 	struct siginfo si;
+	unsigned long address;
 
+	address = trans_exc_code & __FAIL_ADDR_MASK;
+	current->thread.prot_addr = address;
+	current->thread.trap_no = int_code;
 #if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
 #if defined(CONFIG_SYSCTL)
 	if (sysctl_userprocess_debug)
 #endif
 	{
 		printk("User process fault: interruption code 0x%lX\n",
-		       error_code);
+		       int_code);
 		printk("failing address: %lX\n", address);
 		show_regs(regs);
 	}
@@ -144,14 +151,14 @@
 	force_sig_info(SIGSEGV, &si, current);
 }
 
-static void do_no_context(struct pt_regs *regs, unsigned long error_code,
-			  unsigned long trans_exc_code)
+static noinline void do_no_context(struct pt_regs *regs, long int_code,
+				   unsigned long trans_exc_code)
 {
 	const struct exception_table_entry *fixup;
 	unsigned long address;
 
 	/* Are we prepared to handle this kernel fault?  */
-	fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
+	fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
 	if (fixup) {
 		regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 		return;
@@ -169,107 +176,127 @@
 		printk(KERN_ALERT "Unable to handle kernel paging request"
 		       " at virtual user address %p\n", (void *)address);
 
-	die("Oops", regs, error_code);
+	die("Oops", regs, int_code);
 	do_exit(SIGKILL);
 }
 
-static void do_low_address(struct pt_regs *regs, unsigned long error_code,
-			   unsigned long trans_exc_code)
+static noinline void do_low_address(struct pt_regs *regs, long int_code,
+				    unsigned long trans_exc_code)
 {
 	/* Low-address protection hit in kernel mode means
 	   NULL pointer write access in kernel mode.  */
 	if (regs->psw.mask & PSW_MASK_PSTATE) {
 		/* Low-address protection hit in user mode 'cannot happen'. */
-		die ("Low-address protection", regs, error_code);
+		die ("Low-address protection", regs, int_code);
 		do_exit(SIGKILL);
 	}
 
-	do_no_context(regs, error_code, trans_exc_code);
+	do_no_context(regs, int_code, trans_exc_code);
 }
 
-static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
-		      unsigned long trans_exc_code)
+static noinline void do_sigbus(struct pt_regs *regs, long int_code,
+			       unsigned long trans_exc_code)
 {
 	struct task_struct *tsk = current;
-	struct mm_struct *mm = tsk->mm;
 
-	up_read(&mm->mmap_sem);
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
 	tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
-	tsk->thread.trap_no = error_code;
+	tsk->thread.trap_no = int_code;
 	force_sig(SIGBUS, tsk);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!(regs->psw.mask & PSW_MASK_PSTATE))
-		do_no_context(regs, error_code, trans_exc_code);
 }
 
 #ifdef CONFIG_S390_EXEC_PROTECT
-static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
-			 unsigned long address, unsigned long error_code)
+static noinline int signal_return(struct pt_regs *regs, long int_code,
+				  unsigned long trans_exc_code)
 {
 	u16 instruction;
 	int rc;
-#ifdef CONFIG_COMPAT
-	int compat;
-#endif
 
-	pagefault_disable();
 	rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
-	pagefault_enable();
-	if (rc)
-		return -EFAULT;
 
-	up_read(&mm->mmap_sem);
-	clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
-#ifdef CONFIG_COMPAT
-	compat = is_compat_task();
-	if (compat && instruction == 0x0a77)
-		sys32_sigreturn();
-	else if (compat && instruction == 0x0aad)
-		sys32_rt_sigreturn();
-	else
-#endif
-	if (instruction == 0x0a77)
-		sys_sigreturn();
-	else if (instruction == 0x0aad)
-		sys_rt_sigreturn();
-	else {
-		current->thread.prot_addr = address;
-		current->thread.trap_no = error_code;
-		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
-	}
+	if (!rc && instruction == 0x0a77) {
+		clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+		if (is_compat_task())
+			sys32_sigreturn();
+		else
+			sys_sigreturn();
+	} else if (!rc && instruction == 0x0aad) {
+		clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+		if (is_compat_task())
+			sys32_rt_sigreturn();
+		else
+			sys_rt_sigreturn();
+	} else
+		do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
 	return 0;
 }
 #endif /* CONFIG_S390_EXEC_PROTECT */
 
+static noinline void do_fault_error(struct pt_regs *regs, long int_code,
+				    unsigned long trans_exc_code, int fault)
+{
+	int si_code;
+
+	switch (fault) {
+	case VM_FAULT_BADACCESS:
+#ifdef CONFIG_S390_EXEC_PROTECT
+		if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+		    (trans_exc_code & 3) == 0) {
+			signal_return(regs, int_code, trans_exc_code);
+			break;
+		}
+#endif /* CONFIG_S390_EXEC_PROTECT */
+	case VM_FAULT_BADMAP:
+		/* Bad memory access. Check if it is kernel or user space. */
+		if (regs->psw.mask & PSW_MASK_PSTATE) {
+			/* User mode accesses just cause a SIGSEGV */
+			si_code = (fault == VM_FAULT_BADMAP) ?
+				SEGV_MAPERR : SEGV_ACCERR;
+			do_sigsegv(regs, int_code, si_code, trans_exc_code);
+			return;
+		}
+	case VM_FAULT_BADCONTEXT:
+		do_no_context(regs, int_code, trans_exc_code);
+		break;
+	default: /* fault & VM_FAULT_ERROR */
+		if (fault & VM_FAULT_OOM)
+			pagefault_out_of_memory();
+		else if (fault & VM_FAULT_SIGBUS) {
+			do_sigbus(regs, int_code, trans_exc_code);
+			/* Kernel mode? Handle exceptions or die */
+			if (!(regs->psw.mask & PSW_MASK_PSTATE))
+				do_no_context(regs, int_code, trans_exc_code);
+		} else
+			BUG();
+		break;
+	}
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  *
- * error_code:
+ * interruption code (int_code):
  *   04       Protection           ->  Write-Protection  (suprression)
  *   10       Segment translation  ->  Not present       (nullification)
  *   11       Page translation     ->  Not present       (nullification)
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
-static inline void
-do_exception(struct pt_regs *regs, unsigned long error_code, int write,
-	     unsigned long trans_exc_code)
+static inline int do_exception(struct pt_regs *regs, int write,
+			       unsigned long trans_exc_code)
 {
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	struct vm_area_struct *vma;
 	unsigned long address;
-	int si_code;
 	int fault;
 
 	if (notify_page_fault(regs))
-		return;
+		return 0;
 
 	tsk = current;
 	mm = tsk->mm;
@@ -279,8 +306,9 @@
 	 * we are not in an interrupt and that there is a 
 	 * user context.
 	 */
+	fault = VM_FAULT_BADCONTEXT;
 	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
-		goto no_context;
+		goto out;
 
 	address = trans_exc_code & __FAIL_ADDR_MASK;
 	/*
@@ -292,41 +320,35 @@
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 	down_read(&mm->mmap_sem);
 
-	si_code = SEGV_MAPERR;
+	fault = VM_FAULT_BADMAP;
 	vma = find_vma(mm, address);
 	if (!vma)
-		goto bad_area;
+		goto out_up;
 
+	if (unlikely(vma->vm_start > address)) {
+		if (!(vma->vm_flags & VM_GROWSDOWN))
+			goto out_up;
+		if (expand_stack(vma, address))
+			goto out_up;
+	}
+
+	/*
+	 * Ok, we have a good vm_area for this memory access, so
+	 * we can handle it..
+	 */
+	fault = VM_FAULT_BADACCESS;
 #ifdef CONFIG_S390_EXEC_PROTECT
 	if (unlikely((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
 		     (trans_exc_code & 3) == 0 && !(vma->vm_flags & VM_EXEC)))
-		if (!signal_return(mm, regs, address, error_code))
-			/*
-			 * signal_return() has done an up_read(&mm->mmap_sem)
-			 * if it returns 0.
-			 */
-			return;
+		goto out_up;
 #endif
-
-	if (vma->vm_start <= address)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-	if (expand_stack(vma, address))
-		goto bad_area;
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
-	si_code = SEGV_ACCERR;
 	if (!write) {
 		/* page not present, check vm flags */
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-			goto bad_area;
+			goto out_up;
 	} else {
 		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
+			goto out_up;
 	}
 
 	if (is_vm_hugetlb_page(vma))
@@ -337,17 +359,9 @@
 	 * the fault.
 	 */
 	fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(fault & VM_FAULT_ERROR)) {
-		if (fault & VM_FAULT_OOM) {
-			up_read(&mm->mmap_sem);
-			pagefault_out_of_memory();
-			return;
-		} else if (fault & VM_FAULT_SIGBUS) {
-			do_sigbus(regs, error_code, address);
-			return;
-		}
-		BUG();
-	}
+	if (unlikely(fault & VM_FAULT_ERROR))
+		goto out_up;
+
 	if (fault & VM_FAULT_MAJOR) {
 		tsk->maj_flt++;
 		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
@@ -357,67 +371,55 @@
 		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
 				     regs, address);
 	}
-        up_read(&mm->mmap_sem);
 	/*
 	 * The instruction that caused the program check will
 	 * be repeated. Don't signal single step via SIGTRAP.
 	 */
 	clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
-        return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
+	fault = 0;
+out_up:
 	up_read(&mm->mmap_sem);
-
-	/* User mode accesses just cause a SIGSEGV */
-	if (regs->psw.mask & PSW_MASK_PSTATE) {
-		tsk->thread.prot_addr = address;
-		tsk->thread.trap_no = error_code;
-		do_sigsegv(regs, error_code, si_code, address);
-		return;
-	}
-
-no_context:
-	do_no_context(regs, error_code, trans_exc_code);
+out:
+	return fault;
 }
 
-void __kprobes do_protection_exception(struct pt_regs *regs,
-				       long error_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
 {
 	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+	int fault;
 
 	/* Protection exception is supressing, decrement psw address. */
-	regs->psw.addr -= (error_code >> 16);
+	regs->psw.addr -= (int_code >> 16);
 	/*
 	 * Check for low-address protection.  This needs to be treated
 	 * as a special case because the translation exception code
 	 * field is not guaranteed to contain valid data in this case.
 	 */
 	if (unlikely(!(trans_exc_code & 4))) {
-		do_low_address(regs, error_code, trans_exc_code);
+		do_low_address(regs, int_code, trans_exc_code);
 		return;
 	}
-	do_exception(regs, 4, 1, trans_exc_code);
+	fault = do_exception(regs, 1, trans_exc_code);
+	if (unlikely(fault))
+		do_fault_error(regs, 4, trans_exc_code, fault);
 }
 
-void __kprobes do_dat_exception(struct pt_regs *regs, long error_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
 {
-	do_exception(regs, error_code & 0xff, 0, S390_lowcore.trans_exc_code);
+	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+	int fault;
+
+	fault = do_exception(regs, 0, trans_exc_code);
+	if (unlikely(fault))
+		do_fault_error(regs, int_code & 255, trans_exc_code, fault);
 }
 
 #ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
 {
 	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
-	struct mm_struct *mm;
+	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
-	unsigned long address;
-
-	mm = current->mm;
-	address = trans_exc_code & __FAIL_ADDR_MASK;
 
 	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
 		goto no_context;
@@ -425,7 +427,7 @@
 	local_irq_enable();
 
 	down_read(&mm->mmap_sem);
-	vma = find_vma(mm, address);
+	vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
 	up_read(&mm->mmap_sem);
 
 	if (vma) {
@@ -435,14 +437,12 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (regs->psw.mask & PSW_MASK_PSTATE) {
-		current->thread.prot_addr = address;
-		current->thread.trap_no = error_code;
-		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+		do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
 		return;
 	}
 
 no_context:
-	do_no_context(regs, error_code, trans_exc_code);
+	do_no_context(regs, int_code, trans_exc_code);
 }
 #endif
 
@@ -507,7 +507,7 @@
 		: : "a" (&refbk), "m" (refbk) : "cc");
 }
 
-static void pfault_interrupt(__u16 error_code)
+static void pfault_interrupt(__u16 int_code)
 {
 	struct task_struct *tsk;
 	__u16 subcode;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 05/52] [PATCH] fault handler access flags check.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (3 preceding siblings ...)
  2009-11-13 15:08 ` [patch 04/52] [PATCH] fault handler performance optimization Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 06/52] [PATCH] Use do_exception() in pagetable walk usercopy functions Martin Schwidefsky
                   ` (47 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 104-mm-fault-access.diff --]
[-- Type: text/plain, Size: 2700 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Simplify the check of the vma->flags in do_exception for the
different fault types.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/mm/fault.c |   30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
+++ quilt-2.6/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
@@ -286,7 +286,7 @@
  *   11       Page translation     ->  Not present       (nullification)
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
-static inline int do_exception(struct pt_regs *regs, int write,
+static inline int do_exception(struct pt_regs *regs, int access,
 			       unsigned long trans_exc_code)
 {
 	struct task_struct *tsk;
@@ -337,19 +337,8 @@
 	 * we can handle it..
 	 */
 	fault = VM_FAULT_BADACCESS;
-#ifdef CONFIG_S390_EXEC_PROTECT
-	if (unlikely((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
-		     (trans_exc_code & 3) == 0 && !(vma->vm_flags & VM_EXEC)))
+	if (unlikely(!(vma->vm_flags & access)))
 		goto out_up;
-#endif
-	if (!write) {
-		/* page not present, check vm flags */
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-			goto out_up;
-	} else {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto out_up;
-	}
 
 	if (is_vm_hugetlb_page(vma))
 		address &= HPAGE_MASK;
@@ -358,7 +347,8 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+	fault = handle_mm_fault(mm, vma, address,
+				(access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
 	if (unlikely(fault & VM_FAULT_ERROR))
 		goto out_up;
 
@@ -399,7 +389,7 @@
 		do_low_address(regs, int_code, trans_exc_code);
 		return;
 	}
-	fault = do_exception(regs, 1, trans_exc_code);
+	fault = do_exception(regs, VM_WRITE, trans_exc_code);
 	if (unlikely(fault))
 		do_fault_error(regs, 4, trans_exc_code, fault);
 }
@@ -407,9 +397,15 @@
 void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
 {
 	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
-	int fault;
+	int access, fault;
 
-	fault = do_exception(regs, 0, trans_exc_code);
+	access = VM_READ | VM_EXEC | VM_WRITE;
+#ifdef CONFIG_S390_EXEC_PROTECT
+	if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+	    (trans_exc_code & 3) == 0)
+		access = VM_EXEC;
+#endif
+	fault = do_exception(regs, access, trans_exc_code);
 	if (unlikely(fault))
 		do_fault_error(regs, int_code & 255, trans_exc_code, fault);
 }

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 06/52] [PATCH] Use do_exception() in pagetable walk usercopy functions.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (4 preceding siblings ...)
  2009-11-13 15:08 ` [patch 05/52] [PATCH] fault handler access flags check Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 07/52] [PATCH] Improve code generated by atomic operations Martin Schwidefsky
                   ` (46 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Gerald Schaefer, Martin Schwidefsky

[-- Attachment #1: 105-mm-pt-walk.diff --]
[-- Type: text/plain, Size: 8608 bytes --]

From: Gerald Schaefer <gerald.schaefer@de.ibm.com>

The pagetable walk usercopy functions have used a modified copy of the
do_exception() function for fault handling. This lead to inconsistencies
with recent changes to do_exception(), e.g. performance counters. This
patch changes the pagetable walk usercopy code to call do_exception()
directly, eliminating the redundancy. A new parameter is added to
do_exception() to specify the fault address.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/include/asm/uaccess.h |    2 
 arch/s390/lib/uaccess_pt.c      |  147 +++++++++++++---------------------------
 arch/s390/mm/fault.c            |   23 ++++++
 3 files changed, 76 insertions(+), 96 deletions(-)

Index: quilt-2.6/arch/s390/include/asm/uaccess.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/uaccess.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/uaccess.h	2009-11-13 16:08:13.000000000 +0100
@@ -93,6 +93,8 @@
 extern struct uaccess_ops uaccess_mvcos_switch;
 extern struct uaccess_ops uaccess_pt;
 
+extern int __handle_fault(unsigned long, unsigned long, int);
+
 static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
 {
 	size = uaccess.copy_to_user_small(size, ptr, x);
Index: quilt-2.6/arch/s390/lib/uaccess_pt.c
===================================================================
--- quilt-2.6.orig/arch/s390/lib/uaccess_pt.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/lib/uaccess_pt.c	2009-11-13 16:08:13.000000000 +0100
@@ -23,86 +23,21 @@
 
 	pgd = pgd_offset(mm, addr);
 	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-		return NULL;
+		return (pte_t *) 0x3a;
 
 	pud = pud_offset(pgd, addr);
 	if (pud_none(*pud) || unlikely(pud_bad(*pud)))
-		return NULL;
+		return (pte_t *) 0x3b;
 
 	pmd = pmd_offset(pud, addr);
 	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-		return NULL;
+		return (pte_t *) 0x10;
 
 	return pte_offset_map(pmd, addr);
 }
 
-static int __handle_fault(struct mm_struct *mm, unsigned long address,
-			  int write_access)
-{
-	struct vm_area_struct *vma;
-	int ret = -EFAULT;
-	int fault;
-
-	if (in_atomic())
-		return ret;
-	down_read(&mm->mmap_sem);
-	vma = find_vma(mm, address);
-	if (unlikely(!vma))
-		goto out;
-	if (unlikely(vma->vm_start > address)) {
-		if (!(vma->vm_flags & VM_GROWSDOWN))
-			goto out;
-		if (expand_stack(vma, address))
-			goto out;
-	}
-
-	if (!write_access) {
-		/* page not present, check vm flags */
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-			goto out;
-	} else {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto out;
-	}
-
-survive:
-	fault = handle_mm_fault(mm, vma, address, write_access ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(fault & VM_FAULT_ERROR)) {
-		if (fault & VM_FAULT_OOM)
-			goto out_of_memory;
-		else if (fault & VM_FAULT_SIGBUS)
-			goto out_sigbus;
-		BUG();
-	}
-	if (fault & VM_FAULT_MAJOR)
-		current->maj_flt++;
-	else
-		current->min_flt++;
-	ret = 0;
-out:
-	up_read(&mm->mmap_sem);
-	return ret;
-
-out_of_memory:
-	up_read(&mm->mmap_sem);
-	if (is_global_init(current)) {
-		yield();
-		down_read(&mm->mmap_sem);
-		goto survive;
-	}
-	printk("VM: killing process %s\n", current->comm);
-	return ret;
-
-out_sigbus:
-	up_read(&mm->mmap_sem);
-	current->thread.prot_addr = address;
-	current->thread.trap_no = 0x11;
-	force_sig(SIGBUS, current);
-	return ret;
-}
-
-static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
-			     size_t n, int write_user)
+static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+					     size_t n, int write_user)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long offset, pfn, done, size;
@@ -114,12 +49,17 @@
 	spin_lock(&mm->page_table_lock);
 	do {
 		pte = follow_table(mm, uaddr);
-		if (!pte || !pte_present(*pte) ||
-		    (write_user && !pte_write(*pte)))
+		if ((unsigned long) pte < 0x1000)
 			goto fault;
+		if (!pte_present(*pte)) {
+			pte = (pte_t *) 0x11;
+			goto fault;
+		} else if (write_user && !pte_write(*pte)) {
+			pte = (pte_t *) 0x04;
+			goto fault;
+		}
 
 		pfn = pte_pfn(*pte);
-
 		offset = uaddr & (PAGE_SIZE - 1);
 		size = min(n - done, PAGE_SIZE - offset);
 		if (write_user) {
@@ -137,7 +77,7 @@
 	return n - done;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	if (__handle_fault(mm, uaddr, write_user))
+	if (__handle_fault(uaddr, (unsigned long) pte, write_user))
 		return n - done;
 	goto retry;
 }
@@ -146,30 +86,31 @@
  * Do DAT for user address by page table walk, return kernel address.
  * This function needs to be called with current->mm->page_table_lock held.
  */
-static unsigned long __dat_user_addr(unsigned long uaddr)
+static __always_inline unsigned long __dat_user_addr(unsigned long uaddr)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long pfn, ret;
+	unsigned long pfn;
 	pte_t *pte;
 	int rc;
 
-	ret = 0;
 retry:
 	pte = follow_table(mm, uaddr);
-	if (!pte || !pte_present(*pte))
+	if ((unsigned long) pte < 0x1000)
 		goto fault;
+	if (!pte_present(*pte)) {
+		pte = (pte_t *) 0x11;
+		goto fault;
+	}
 
 	pfn = pte_pfn(*pte);
-	ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
-out:
-	return ret;
+	return (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
 fault:
 	spin_unlock(&mm->page_table_lock);
-	rc = __handle_fault(mm, uaddr, 0);
+	rc = __handle_fault(uaddr, (unsigned long) pte, 0);
 	spin_lock(&mm->page_table_lock);
-	if (rc)
-		goto out;
-	goto retry;
+	if (!rc)
+		goto retry;
+	return 0;
 }
 
 size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
@@ -234,8 +175,12 @@
 	spin_lock(&mm->page_table_lock);
 	do {
 		pte = follow_table(mm, uaddr);
-		if (!pte || !pte_present(*pte))
+		if ((unsigned long) pte < 0x1000)
+			goto fault;
+		if (!pte_present(*pte)) {
+			pte = (pte_t *) 0x11;
 			goto fault;
+		}
 
 		pfn = pte_pfn(*pte);
 		offset = uaddr & (PAGE_SIZE-1);
@@ -249,9 +194,8 @@
 	return done + 1;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	if (__handle_fault(mm, uaddr, 0)) {
+	if (__handle_fault(uaddr, (unsigned long) pte, 0))
 		return 0;
-	}
 	goto retry;
 }
 
@@ -284,7 +228,7 @@
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
-		      uaddr, done, size;
+		      uaddr, done, size, error_code;
 	unsigned long uaddr_from = (unsigned long) from;
 	unsigned long uaddr_to = (unsigned long) to;
 	pte_t *pte_from, *pte_to;
@@ -298,17 +242,28 @@
 retry:
 	spin_lock(&mm->page_table_lock);
 	do {
+		write_user = 0;
+		uaddr = uaddr_from;
 		pte_from = follow_table(mm, uaddr_from);
-		if (!pte_from || !pte_present(*pte_from)) {
-			uaddr = uaddr_from;
-			write_user = 0;
+		error_code = (unsigned long) pte_from;
+		if (error_code < 0x1000)
+			goto fault;
+		if (!pte_present(*pte_from)) {
+			error_code = 0x11;
 			goto fault;
 		}
 
+		write_user = 1;
+		uaddr = uaddr_to;
 		pte_to = follow_table(mm, uaddr_to);
-		if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
-			uaddr = uaddr_to;
-			write_user = 1;
+		error_code = (unsigned long) pte_to;
+		if (error_code < 0x1000)
+			goto fault;
+		if (!pte_present(*pte_to)) {
+			error_code = 0x11;
+			goto fault;
+		} else if (!pte_write(*pte_to)) {
+			error_code = 0x04;
 			goto fault;
 		}
 
@@ -329,7 +284,7 @@
 	return n - done;
 fault:
 	spin_unlock(&mm->page_table_lock);
-	if (__handle_fault(mm, uaddr, write_user))
+	if (__handle_fault(uaddr, error_code, write_user))
 		return n - done;
 	goto retry;
 }
Index: quilt-2.6/arch/s390/mm/fault.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/fault.c	2009-11-13 16:08:12.000000000 +0100
+++ quilt-2.6/arch/s390/mm/fault.c	2009-11-13 16:08:13.000000000 +0100
@@ -442,6 +442,29 @@
 }
 #endif
 
+int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+{
+	struct pt_regs regs;
+	int access, fault;
+
+	regs.psw.mask = psw_kernel_bits;
+	if (!irqs_disabled())
+		regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
+	regs.psw.addr = (unsigned long) __builtin_return_address(0);
+	regs.psw.addr |= PSW_ADDR_AMODE;
+	uaddr &= PAGE_MASK;
+	access = write_user ? VM_WRITE : VM_READ;
+	fault = do_exception(&regs, access, uaddr | 2);
+	if (unlikely(fault)) {
+		if (fault & VM_FAULT_OOM) {
+			pagefault_out_of_memory();
+			fault = 0;
+		} else if (fault & VM_FAULT_SIGBUS)
+			do_sigbus(&regs, int_code, uaddr);
+	}
+	return fault ? -EFAULT : 0;
+}
+
 #ifdef CONFIG_PFAULT 
 /*
  * 'pfault' pseudo page faults routines.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 07/52] [PATCH] Improve code generated by atomic operations.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (5 preceding siblings ...)
  2009-11-13 15:08 ` [patch 06/52] [PATCH] Use do_exception() in pagetable walk usercopy functions Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 08/52] [PATCH] dasd: support DIAG access for read-only devices Martin Schwidefsky
                   ` (45 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Matthew Wilcox, Martin Schwidefsky

[-- Attachment #1: 106-atomic-volatile.diff --]
[-- Type: text/plain, Size: 2395 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Git commit ea435467500612636f8f4fb639ff6e76b2496e4b changed the
definition of atomic_t and atomic64_t for s390 by adding the volatile
modifier to the counter field. This has an unfortunate side effect
with newer versions of the gcc. The typeof operator now picks up the
volatile modifier from the expression. This causes the compiler to
think that it has to store the two temporary variable old_val and
new_val in the __CS_LOOP for the different atomic operations to the
stack as the variables are now volatile. Both stores are superfluous.

The hack to replace typeof(ptr->counter) with int in __CS_LOOP and
and long long in __CSG_LOOP avoids the two stores. A better solution
would be to drop the volatile from the counter field of the atomic_t
and atomic64_t definition. But that is a touchy subject ..

Cc: Matthew Wilcox <matthew@wil.cx>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/include/asm/atomic.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Index: quilt-2.6/arch/s390/include/asm/atomic.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/atomic.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/atomic.h	2009-11-13 16:08:13.000000000 +0100
@@ -21,7 +21,7 @@
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
 
 #define __CS_LOOP(ptr, op_val, op_string) ({				\
-	typeof(ptr->counter) old_val, new_val;				\
+	int old_val, new_val;						\
 	asm volatile(							\
 		"	l	%0,%2\n"				\
 		"0:	lr	%1,%0\n"				\
@@ -38,7 +38,7 @@
 #else /* __GNUC__ */
 
 #define __CS_LOOP(ptr, op_val, op_string) ({				\
-	typeof(ptr->counter) old_val, new_val;				\
+	int old_val, new_val;						\
 	asm volatile(							\
 		"	l	%0,0(%3)\n"				\
 		"0:	lr	%1,%0\n"				\
@@ -143,7 +143,7 @@
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
 
 #define __CSG_LOOP(ptr, op_val, op_string) ({				\
-	typeof(ptr->counter) old_val, new_val;				\
+	long long old_val, new_val;					\
 	asm volatile(							\
 		"	lg	%0,%2\n"				\
 		"0:	lgr	%1,%0\n"				\
@@ -160,7 +160,7 @@
 #else /* __GNUC__ */
 
 #define __CSG_LOOP(ptr, op_val, op_string) ({				\
-	typeof(ptr->counter) old_val, new_val;				\
+	long long old_val, new_val;					\
 	asm volatile(							\
 		"	lg	%0,0(%3)\n"				\
 		"0:	lgr	%1,%0\n"				\

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 08/52] [PATCH] dasd: support DIAG access for read-only devices
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (6 preceding siblings ...)
  2009-11-13 15:08 ` [patch 07/52] [PATCH] Improve code generated by atomic operations Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 09/52] [PATCH] cmm: free pages on hibernate Martin Schwidefsky
                   ` (44 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Stefan Weinhuber, Martin Schwidefsky

[-- Attachment #1: 107-dasd-diag-ro.diff --]
[-- Type: text/plain, Size: 2346 bytes --]

From: Stefan Weinhuber <wein@de.ibm.com>

When a DASD device is used with the DIAG discipline, the DIAG
initialization will indicate success or error with a respective
return code. So far we have interpreted a return code of 4 as error,
but it actually means that the initialization was successful, but
the device is read-only. To allow read-only devices to be used with
DIAG we need to accept a return code of 4 as success.

Re-initialization of the DIAG access is also part of the DIAG error
recovery. If we find that the access mode of a device has been
changed from writable to read-only while the device was in use,
we print an error message.

Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/block/dasd_diag.c |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

Index: quilt-2.6/drivers/s390/block/dasd_diag.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_diag.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_diag.c	2009-11-13 16:08:13.000000000 +0100
@@ -145,6 +145,15 @@
 
 	mdsk_term_io(device);
 	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
+	if (rc == 4) {
+		if (!(device->features & DASD_FEATURE_READONLY)) {
+			dev_warn(&device->cdev->dev,
+				 "The access mode of a DIAG device changed"
+				 " to read-only");
+			device->features |= DASD_FEATURE_READONLY;
+		}
+		rc = 0;
+	}
 	if (rc)
 		dev_warn(&device->cdev->dev, "DIAG ERP failed with "
 			    "rc=%d\n", rc);
@@ -433,16 +442,20 @@
 	for (sb = 512; sb < bsize; sb = sb << 1)
 		block->s2b_shift++;
 	rc = mdsk_init_io(device, block->bp_block, 0, NULL);
-	if (rc) {
+	if (rc && (rc != 4)) {
 		dev_warn(&device->cdev->dev, "DIAG initialization "
 			"failed with rc=%d\n", rc);
 		rc = -EIO;
 	} else {
+		if (rc == 4)
+			device->features |= DASD_FEATURE_READONLY;
 		dev_info(&device->cdev->dev,
-			 "New DASD with %ld byte/block, total size %ld KB\n",
+			 "New DASD with %ld byte/block, total size %ld KB%s\n",
 			 (unsigned long) block->bp_block,
 			 (unsigned long) (block->blocks <<
-					  block->s2b_shift) >> 1);
+					  block->s2b_shift) >> 1,
+			 (rc == 4) ? ", read-only device" : "");
+		rc = 0;
 	}
 out_label:
 	free_page((long) label);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 09/52] [PATCH] cmm: free pages on hibernate.
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (7 preceding siblings ...)
  2009-11-13 15:08 ` [patch 08/52] [PATCH] dasd: support DIAG access for read-only devices Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 10/52] [PATCH] smp: remove unused typedef and defines Martin Schwidefsky
                   ` (43 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 108-cmm-suspend.diff --]
[-- Type: text/plain, Size: 3872 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The pages allocated by the cmm memory balloon should be freed before
the hibernation image is created. Otherwise the memory reserved by the
balloon gets written to the swap device but there is no content in
these pages that need to be preserved.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/mm/cmm.c |   61 +++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 50 insertions(+), 11 deletions(-)

Index: quilt-2.6/arch/s390/mm/cmm.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/cmm.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/mm/cmm.c	2009-11-13 16:08:14.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/swap.h>
 #include <linux/kthread.h>
 #include <linux/oom.h>
+#include <linux/suspend.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -44,6 +45,7 @@
 static volatile long cmm_timed_pages_target;
 static long cmm_timeout_pages;
 static long cmm_timeout_seconds;
+static int cmm_suspended;
 
 static struct cmm_page_array *cmm_page_list;
 static struct cmm_page_array *cmm_timed_page_list;
@@ -147,9 +149,9 @@
 
 	while (1) {
 		rc = wait_event_interruptible(cmm_thread_wait,
-			(cmm_pages != cmm_pages_target ||
-			 cmm_timed_pages != cmm_timed_pages_target ||
-			 kthread_should_stop()));
+			(!cmm_suspended && (cmm_pages != cmm_pages_target ||
+			 cmm_timed_pages != cmm_timed_pages_target)) ||
+			 kthread_should_stop());
 		if (kthread_should_stop() || rc == -ERESTARTSYS) {
 			cmm_pages_target = cmm_pages;
 			cmm_timed_pages_target = cmm_timed_pages;
@@ -411,6 +413,38 @@
 
 static struct ctl_table_header *cmm_sysctl_header;
 
+static int cmm_suspend(void)
+{
+	cmm_suspended = 1;
+	cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
+	cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
+	return 0;
+}
+
+static int cmm_resume(void)
+{
+	cmm_suspended = 0;
+	cmm_kick_thread();
+	return 0;
+}
+
+static int cmm_power_event(struct notifier_block *this,
+			   unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+		return cmm_resume();
+	case PM_HIBERNATION_PREPARE:
+		return cmm_suspend();
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct notifier_block cmm_power_notifier = {
+	.notifier_call = cmm_power_event,
+};
+
 static int
 cmm_init (void)
 {
@@ -419,7 +453,7 @@
 #ifdef CONFIG_CMM_PROC
 	cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
 	if (!cmm_sysctl_header)
-		goto out;
+		goto out_sysctl;
 #endif
 #ifdef CONFIG_CMM_IUCV
 	rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -429,17 +463,21 @@
 	rc = register_oom_notifier(&cmm_oom_nb);
 	if (rc < 0)
 		goto out_oom_notify;
+	rc = register_pm_notifier(&cmm_power_notifier);
+	if (rc)
+		goto out_pm;
 	init_waitqueue_head(&cmm_thread_wait);
 	init_timer(&cmm_timer);
 	cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
 	rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
-	if (!rc)
-		goto out;
-	/*
-	 * kthread_create failed. undo all the stuff from above again.
-	 */
-	unregister_oom_notifier(&cmm_oom_nb);
+	if (rc)
+		goto out_kthread;
+	return 0;
 
+out_kthread:
+	unregister_pm_notifier(&cmm_power_notifier);
+out_pm:
+	unregister_oom_notifier(&cmm_oom_nb);
 out_oom_notify:
 #ifdef CONFIG_CMM_IUCV
 	smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -447,8 +485,8 @@
 #endif
 #ifdef CONFIG_CMM_PROC
 	unregister_sysctl_table(cmm_sysctl_header);
+out_sysctl:
 #endif
-out:
 	return rc;
 }
 
@@ -456,6 +494,7 @@
 cmm_exit(void)
 {
 	kthread_stop(cmm_thread_ptr);
+	unregister_pm_notifier(&cmm_power_notifier);
 	unregister_oom_notifier(&cmm_oom_nb);
 	cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
 	cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 10/52] [PATCH] smp: remove unused typedef and defines
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (8 preceding siblings ...)
  2009-11-13 15:08 ` [patch 09/52] [PATCH] cmm: free pages on hibernate Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 11/52] [PATCH] dasd: remove dead code Martin Schwidefsky
                   ` (42 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 109-smp-unused.diff --]
[-- Type: text/plain, Size: 3050 bytes --]

From: Heiko Carstens <heiko.carstens@de.ibm.com>

Remove unused typedef, defines, update copyright, remove unneeded
includes, remove unneeded ifdefs.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/include/asm/smp.h |   54 ++++++++------------------------------------
 1 file changed, 10 insertions(+), 44 deletions(-)

Index: quilt-2.6/arch/s390/include/asm/smp.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/smp.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/smp.h	2009-11-13 16:08:14.000000000 +0100
@@ -1,57 +1,22 @@
 /*
- *  include/asm-s390/smp.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- *               Martin Schwidefsky (schwidefsky@de.ibm.com)
- *               Heiko Carstens (heiko.carstens@de.ibm.com)
+ *    Copyright IBM Corp. 1999,2009
+ *    Author(s): Denis Joseph Barrow,
+ *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ *		 Heiko Carstens <heiko.carstens@de.ibm.com>,
  */
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
 
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/bitops.h>
+#ifdef CONFIG_SMP
 
-#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
-
-#include <asm/lowcore.h>
-#include <asm/sigp.h>
-#include <asm/ptrace.h>
 #include <asm/system.h>
-
-/*
-  s390 specific smp.c headers
- */
-typedef struct
-{
-	int        intresting;
-	sigp_ccode ccode; 
-	__u32      status;
-	__u16      cpu;
-} sigp_info;
+#include <asm/sigp.h>
 
 extern void machine_restart_smp(char *);
 extern void machine_halt_smp(void);
 extern void machine_power_off_smp(void);
 
-#define NO_PROC_ID		0xFF		/* No processor magic marker */
-
-/*
- *	This magic constant controls our willingness to transfer
- *	a process across CPUs. Such a transfer incurs misses on the L1
- *	cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
- *	gut feeling is this will vary by board in value. For a board
- *	with separate L2 cache it probably depends also on the RSS, and
- *	for a board with shared L2 cache it ought to decay fast as other
- *	processes are run.
- */
- 
-#define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
-
 #define raw_smp_processor_id()	(S390_lowcore.cpu_nr)
-#define cpu_logical_map(cpu)	(cpu)
 
 extern int __cpu_disable (void);
 extern void __cpu_die (unsigned int cpu);
@@ -64,7 +29,9 @@
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
-#endif
+extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_HOTPLUG_CPU
 extern int smp_rescan_cpus(void);
@@ -72,5 +39,4 @@
 static inline int smp_rescan_cpus(void) { return 0; }
 #endif
 
-extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
-#endif
+#endif /* __ASM_SMP_H */

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 11/52] [PATCH] dasd: remove dead code
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (9 preceding siblings ...)
  2009-11-13 15:08 ` [patch 10/52] [PATCH] smp: remove unused typedef and defines Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 12/52] [PATCH] use generic termbits.h header file Martin Schwidefsky
                   ` (41 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Christian Borntraeger, Martin Schwidefsky

[-- Attachment #1: 110-dasd-dead-code.diff --]
[-- Type: text/plain, Size: 3620 bytes --]

From: Christian Borntraeger <borntraeger@de.ibm.com>

the todclk.h header file is dead code. Remove it.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/include/asm/todclk.h     |   23 -----------------------
 drivers/s390/block/dasd.c          |    1 -
 drivers/s390/block/dasd_3990_erp.c |    1 -
 drivers/s390/block/dasd_diag.c     |    1 -
 drivers/s390/block/dasd_eckd.c     |    1 -
 drivers/s390/block/dasd_fba.c      |    1 -
 6 files changed, 28 deletions(-)

Index: quilt-2.6/arch/s390/include/asm/todclk.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/todclk.h	2009-11-13 15:48:32.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,23 +0,0 @@
-/*
- * File...........: linux/include/asm/todclk.h
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
- * History of changes (starts July 2000)
- */
-
-#ifndef __ASM_TODCLK_H
-#define __ASM_TODCLK_H
-
-#ifdef __KERNEL__
-
-#define TOD_uSEC (0x1000ULL)
-#define TOD_mSEC (1000 * TOD_uSEC)
-#define TOD_SEC (1000 * TOD_mSEC)
-#define TOD_MIN (60 * TOD_SEC)
-#define TOD_HOUR (60 * TOD_MIN)
-
-#endif
-
-#endif
Index: quilt-2.6/drivers/s390/block/dasd_3990_erp.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_3990_erp.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_3990_erp.c	2009-11-13 16:08:14.000000000 +0100
@@ -12,7 +12,6 @@
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <asm/idals.h>
-#include <asm/todclk.h>
 
 #define PRINTK_HEADER "dasd_erp(3990): "
 
Index: quilt-2.6/drivers/s390/block/dasd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd.c	2009-11-13 16:08:14.000000000 +0100
@@ -24,7 +24,6 @@
 #include <asm/ccwdev.h>
 #include <asm/ebcdic.h>
 #include <asm/idals.h>
-#include <asm/todclk.h>
 #include <asm/itcw.h>
 
 /* This is ugly... */
Index: quilt-2.6/drivers/s390/block/dasd_diag.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_diag.c	2009-11-13 16:08:13.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_diag.c	2009-11-13 16:08:14.000000000 +0100
@@ -24,7 +24,6 @@
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/s390_ext.h>
-#include <asm/todclk.h>
 #include <asm/vtoc.h>
 #include <asm/diag.h>
 
Index: quilt-2.6/drivers/s390/block/dasd_eckd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_eckd.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:14.000000000 +0100
@@ -24,7 +24,6 @@
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
-#include <asm/todclk.h>
 #include <asm/uaccess.h>
 #include <asm/cio.h>
 #include <asm/ccwdev.h>
Index: quilt-2.6/drivers/s390/block/dasd_fba.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_fba.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_fba.c	2009-11-13 16:08:14.000000000 +0100
@@ -20,7 +20,6 @@
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
-#include <asm/todclk.h>
 #include <asm/ccwdev.h>
 
 #include "dasd_int.h"

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 12/52] [PATCH] use generic termbits.h header file
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (10 preceding siblings ...)
  2009-11-13 15:08 ` [patch 11/52] [PATCH] dasd: remove dead code Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 13/52] [PATCH] use generic sockios.h " Martin Schwidefsky
                   ` (40 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens

[-- Attachment #1: 111-termbits-generic.diff --]
[-- Type: text/plain, Size: 5367 bytes --]

From: Christian Borntraeger <borntraeger@de.ibm.com>

Index: quilt-2.6/arch/s390/include/asm/termbits.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/termbits.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/termbits.h	2009-11-13 16:08:14.000000000 +0100
@@ -1,206 +1,6 @@
-/*
- *  include/asm-s390/termbits.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/termbits.h"
- */
+#ifndef _ASM_S390_TERMBITS_H
+#define _ASM_S390_TERMBITS_H
 
-#ifndef __ARCH_S390_TERMBITS_H__
-#define __ARCH_S390_TERMBITS_H__
-
-#include <linux/posix_types.h>
-
-typedef unsigned char	cc_t;
-typedef unsigned int	speed_t;
-typedef unsigned int	tcflag_t;
-
-#define NCCS 19
-struct termios {
-	tcflag_t c_iflag;		/* input mode flags */
-	tcflag_t c_oflag;		/* output mode flags */
-	tcflag_t c_cflag;		/* control mode flags */
-	tcflag_t c_lflag;		/* local mode flags */
-	cc_t c_line;			/* line discipline */
-	cc_t c_cc[NCCS];		/* control characters */
-};
-
-struct termios2 {
-	tcflag_t c_iflag;		/* input mode flags */
-	tcflag_t c_oflag;		/* output mode flags */
-	tcflag_t c_cflag;		/* control mode flags */
-	tcflag_t c_lflag;		/* local mode flags */
-	cc_t c_line;			/* line discipline */
-	cc_t c_cc[NCCS];		/* control characters */
-	speed_t c_ispeed;		/* input speed */
-	speed_t c_ospeed;		/* output speed */
-};
-
-struct ktermios {
-	tcflag_t c_iflag;		/* input mode flags */
-	tcflag_t c_oflag;		/* output mode flags */
-	tcflag_t c_cflag;		/* control mode flags */
-	tcflag_t c_lflag;		/* local mode flags */
-	cc_t c_line;			/* line discipline */
-	cc_t c_cc[NCCS];		/* control characters */
-	speed_t c_ispeed;		/* input speed */
-	speed_t c_ospeed;		/* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-#define IGNBRK	0000001
-#define BRKINT	0000002
-#define IGNPAR	0000004
-#define PARMRK	0000010
-#define INPCK	0000020
-#define ISTRIP	0000040
-#define INLCR	0000100
-#define IGNCR	0000200
-#define ICRNL	0000400
-#define IUCLC	0001000
-#define IXON	0002000
-#define IXANY	0004000
-#define IXOFF	0010000
-#define IMAXBEL	0020000
-#define IUTF8	0040000
-
-/* c_oflag bits */
-#define OPOST	0000001
-#define OLCUC	0000002
-#define ONLCR	0000004
-#define OCRNL	0000010
-#define ONOCR	0000020
-#define ONLRET	0000040
-#define OFILL	0000100
-#define OFDEL	0000200
-#define NLDLY	0000400
-#define   NL0	0000000
-#define   NL1	0000400
-#define CRDLY	0003000
-#define   CR0	0000000
-#define   CR1	0001000
-#define   CR2	0002000
-#define   CR3	0003000
-#define TABDLY	0014000
-#define   TAB0	0000000
-#define   TAB1	0004000
-#define   TAB2	0010000
-#define   TAB3	0014000
-#define   XTABS	0014000
-#define BSDLY	0020000
-#define   BS0	0000000
-#define   BS1	0020000
-#define VTDLY	0040000
-#define   VT0	0000000
-#define   VT1	0040000
-#define FFDLY	0100000
-#define   FF0	0000000
-#define   FF1	0100000
-
-/* c_cflag bit meaning */
-#define CBAUD	0010017
-#define  B0	0000000		/* hang up */
-#define  B50	0000001
-#define  B75	0000002
-#define  B110	0000003
-#define  B134	0000004
-#define  B150	0000005
-#define  B200	0000006
-#define  B300	0000007
-#define  B600	0000010
-#define  B1200	0000011
-#define  B1800	0000012
-#define  B2400	0000013
-#define  B4800	0000014
-#define  B9600	0000015
-#define  B19200	0000016
-#define  B38400	0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE	0000060
-#define   CS5	0000000
-#define   CS6	0000020
-#define   CS7	0000040
-#define   CS8	0000060
-#define CSTOPB	0000100
-#define CREAD	0000200
-#define PARENB	0000400
-#define PARODD	0001000
-#define HUPCL	0002000
-#define CLOCAL	0004000
-#define CBAUDEX 0010000
-#define  BOTHER  0010000
-#define  B57600  0010001
-#define  B115200 0010002
-#define  B230400 0010003
-#define  B460800 0010004
-#define   B500000 0010005
-#define   B576000 0010006
-#define   B921600 0010007
-#define  B1000000 0010010
-#define  B1152000 0010011
-#define  B1500000 0010012
-#define  B2000000 0010013
-#define  B2500000 0010014
-#define  B3000000 0010015
-#define  B3500000 0010016
-#define  B4000000 0010017
-#define CIBAUD	  002003600000	/* input baud rate */
-#define CMSPAR	  010000000000		/* mark or space (stick) parity */
-#define CRTSCTS	  020000000000		/* flow control */
-
-#define IBSHIFT	  16		/* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-#define ISIG	0000001
-#define ICANON	0000002
-#define XCASE	0000004
-#define ECHO	0000010
-#define ECHOE	0000020
-#define ECHOK	0000040
-#define ECHONL	0000100
-#define NOFLSH	0000200
-#define TOSTOP	0000400
-#define ECHOCTL	0001000
-#define ECHOPRT	0002000
-#define ECHOKE	0004000
-#define FLUSHO	0010000
-#define PENDIN	0040000
-#define IEXTEN	0100000
-
-/* tcflow() and TCXONC use these */
-#define	TCOOFF		0
-#define	TCOON		1
-#define	TCIOFF		2
-#define	TCION		3
-
-/* tcflush() and TCFLSH use these */
-#define	TCIFLUSH	0
-#define	TCOFLUSH	1
-#define	TCIOFLUSH	2
-
-/* tcsetattr uses these */
-#define	TCSANOW		0
-#define	TCSADRAIN	1
-#define	TCSAFLUSH	2
+#include <asm-generic/termbits.h>
 
 #endif

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 13/52] [PATCH] use generic sockios.h header file
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (11 preceding siblings ...)
  2009-11-13 15:08 ` [patch 12/52] [PATCH] use generic termbits.h header file Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 14/52] [PATCH] MAINTAINERS: Add s390 drivers block Martin Schwidefsky
                   ` (39 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens

[-- Attachment #1: 112-sockios-generic.diff --]
[-- Type: text/plain, Size: 921 bytes --]

From: Christian Borntraeger <borntraeger@de.ibm.com>

Index: quilt-2.6/arch/s390/include/asm/sockios.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/sockios.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/sockios.h	2009-11-13 16:08:14.000000000 +0100
@@ -1,21 +1,6 @@
-/*
- *  include/asm-s390/sockios.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/sockios.h"
- */
+#ifndef _ASM_S390_SOCKIOS_H
+#define _ASM_S390_SOCKIOS_H
 
-#ifndef __ARCH_S390_SOCKIOS__
-#define __ARCH_S390_SOCKIOS__
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN 	0x8901
-#define SIOCSPGRP	0x8902
-#define FIOGETOWN	0x8903
-#define SIOCGPGRP	0x8904
-#define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
-#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
+#include <asm-generic/sockios.h>
 
 #endif

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 14/52] [PATCH] MAINTAINERS: Add s390 drivers block
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (12 preceding siblings ...)
  2009-11-13 15:08 ` [patch 13/52] [PATCH] use generic sockios.h " Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 15/52] [PATCH] zcrypt: initialize ap_messages for cex3 exploitation Martin Schwidefsky
                   ` (38 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Joe Perches, Martin Schwidefsky

[-- Attachment #1: 113-maintainers-update.diff --]
[-- Type: text/plain, Size: 1297 bytes --]

From: Joe Perches <joe@perches.com>

There are currently 4 directories in drivers/s390
(block, char, cio, kvm) without maintainers.

Add drivers/s390/ to the s390 kvm section.
Add the rest to the default s390 section.
Add a W: link for drivers/s390/crypto/

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 MAINTAINERS |    3 +++
 1 file changed, 3 insertions(+)

Index: quilt-2.6/MAINTAINERS
===================================================================
--- quilt-2.6.orig/MAINTAINERS	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/MAINTAINERS	2009-11-13 16:08:15.000000000 +0100
@@ -3063,6 +3063,7 @@
 F:	Documentation/s390/kvm.txt
 F:	arch/s390/include/asm/kvm*
 F:	arch/s390/kvm/
+F:	drivers/s390/kvm/
 
 KEXEC
 M:	Eric Biederman <ebiederm@xmission.com>
@@ -4471,6 +4472,7 @@
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 F:	arch/s390/
+F:	drivers/s390/
 
 S390 NETWORK DRIVERS
 M:	Ursula Braun <ursula.braun@de.ibm.com>
@@ -4486,6 +4488,7 @@
 M:	Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
 M:	linux390@de.ibm.com
 L:	linux-s390@vger.kernel.org
+W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 F:	drivers/s390/crypto/
 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 15/52] [PATCH] zcrypt: initialize ap_messages for cex3 exploitation
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (13 preceding siblings ...)
  2009-11-13 15:08 ` [patch 14/52] [PATCH] MAINTAINERS: Add s390 drivers block Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 16/52] [PATCH] zcrypt: special command support " Martin Schwidefsky
                   ` (37 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Felix Beck, Ralph Wuerthner, Martin Schwidefsky

[-- Attachment #1: 114-cex3-init-msg.diff --]
[-- Type: text/plain, Size: 4636 bytes --]

From: Felix Beck <felix.beck@de.ibm.com>

AP messages need to be initialized, before they will be used. Values
will be zeroized. This will be needed later when introducing support
for the special commands.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/crypto/ap_bus.h        |   11 +++++++++++
 drivers/s390/crypto/zcrypt_cex2a.c  |    2 ++
 drivers/s390/crypto/zcrypt_pcica.c  |    2 ++
 drivers/s390/crypto/zcrypt_pcicc.c  |    2 ++
 drivers/s390/crypto/zcrypt_pcixcc.c |    5 +++++
 5 files changed, 22 insertions(+)

Index: quilt-2.6/drivers/s390/crypto/ap_bus.h
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/ap_bus.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/ap_bus.h	2009-11-13 16:08:15.000000000 +0100
@@ -167,6 +167,17 @@
 	.dev_type=(dt),					\
 	.match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
 
+/**
+ * ap_init_message() - Initialize ap_message.
+ * Initialize a message before using. Otherwise this might result in
+ * unexpected behaviour.
+ */
+extern inline void ap_init_message(struct ap_message *ap_msg)
+{
+	ap_msg->psmid = 0;
+	ap_msg->length = 0;
+}
+
 /*
  * Note: don't use ap_send/ap_recv after using ap_queue_message
  * for the first time. Otherwise the ap message queue will get
Index: quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:15.000000000 +0100
@@ -298,6 +298,7 @@
 	struct completion work;
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -335,6 +336,7 @@
 	struct completion work;
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcica.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcica.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcica.c	2009-11-13 16:08:15.000000000 +0100
@@ -281,6 +281,7 @@
 	struct completion work;
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -318,6 +319,7 @@
 	struct completion work;
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcicc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcicc.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcicc.c	2009-11-13 16:08:15.000000000 +0100
@@ -483,6 +483,7 @@
 	struct completion work;
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -521,6 +522,7 @@
 	struct completion work;
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:15.000000000 +0100
@@ -688,6 +688,7 @@
 	};
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -727,6 +728,7 @@
 	};
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -766,6 +768,7 @@
 	};
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -805,6 +808,7 @@
 	};
 	int rc;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;
@@ -972,6 +976,7 @@
 	} __attribute__((packed)) *reply;
 	int rc, i;
 
+	ap_init_message(&ap_msg);
 	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
 	if (!ap_msg.message)
 		return -ENOMEM;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 16/52] [PATCH] zcrypt: special command support for cex3 exploitation
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (14 preceding siblings ...)
  2009-11-13 15:08 ` [patch 15/52] [PATCH] zcrypt: initialize ap_messages for cex3 exploitation Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 17/52] [PATCH] zcrypt: add support for cex3 device types Martin Schwidefsky
                   ` (36 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Felix Beck, Ralph Wuerthner, Martin Schwidefsky

[-- Attachment #1: 115-cex3-special-command.diff --]
[-- Type: text/plain, Size: 5604 bytes --]

From: Felix Beck <felix.beck@de.ibm.com>

Support for special command is implemented in the AP Bus in the NQAP
function __ap_send. This is extended for a further parameter special.
When set, the special bit, in GR0 will be set. Therefor the ap_message
struct is extended for a further bit. Thus calling functions of
__ap_send can use the special parameter in ap_message to give to
__ap_send. Affected is in the first place ap_queue_message, which is
called by the actual card driver. The second part of this support is
that the card driver for the CEX3C needs to set this special bit, when
an according CPRB is sent to the driver.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/crypto/ap_bus.c        |   20 +++++++++++++++-----
 drivers/s390/crypto/ap_bus.h        |    3 +++
 drivers/s390/crypto/zcrypt_pcixcc.c |    5 +++++
 3 files changed, 23 insertions(+), 5 deletions(-)

Index: quilt-2.6/drivers/s390/crypto/ap_bus.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/ap_bus.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/ap_bus.c	2009-11-13 16:08:15.000000000 +0100
@@ -282,6 +282,7 @@
  * @psmid: The program supplied message identifier
  * @msg: The message text
  * @length: The message length
+ * @special: Special Bit
  *
  * Returns AP queue status structure.
  * Condition code 1 on NQAP can't happen because the L bit is 1.
@@ -289,7 +290,8 @@
  * because a segment boundary was reached. The NQAP is repeated.
  */
 static inline struct ap_queue_status
-__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
+	  unsigned int special)
 {
 	typedef struct { char _[length]; } msgblock;
 	register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
@@ -299,6 +301,9 @@
 	register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
 	register unsigned long reg5 asm ("5") = (unsigned int) psmid;
 
+	if (special == 1)
+		reg0 |= 0x400000UL;
+
 	asm volatile (
 		"0: .long 0xb2ad0042\n"		/* DQAP */
 		"   brc   2,0b"
@@ -312,13 +317,15 @@
 {
 	struct ap_queue_status status;
 
-	status = __ap_send(qid, psmid, msg, length);
+	status = __ap_send(qid, psmid, msg, length, 0);
 	switch (status.response_code) {
 	case AP_RESPONSE_NORMAL:
 		return 0;
 	case AP_RESPONSE_Q_FULL:
 	case AP_RESPONSE_RESET_IN_PROGRESS:
 		return -EBUSY;
+	case AP_RESPONSE_REQ_FAC_NOT_INST:
+		return -EINVAL;
 	default:	/* Device is gone. */
 		return -ENODEV;
 	}
@@ -1008,7 +1015,7 @@
 	}
 
 	status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
-			   msg, sizeof(msg));
+			   msg, sizeof(msg), 0);
 	if (status.response_code != AP_RESPONSE_NORMAL) {
 		rc = -ENODEV;
 		goto out_free;
@@ -1243,7 +1250,7 @@
 	/* Start the next request on the queue. */
 	ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
 	status = __ap_send(ap_dev->qid, ap_msg->psmid,
-			   ap_msg->message, ap_msg->length);
+			   ap_msg->message, ap_msg->length, ap_msg->special);
 	switch (status.response_code) {
 	case AP_RESPONSE_NORMAL:
 		atomic_inc(&ap_poll_requests);
@@ -1261,6 +1268,7 @@
 		*flags |= 2;
 		break;
 	case AP_RESPONSE_MESSAGE_TOO_BIG:
+	case AP_RESPONSE_REQ_FAC_NOT_INST:
 		return -EINVAL;
 	default:
 		return -ENODEV;
@@ -1302,7 +1310,8 @@
 	if (list_empty(&ap_dev->requestq) &&
 	    ap_dev->queue_count < ap_dev->queue_depth) {
 		status = __ap_send(ap_dev->qid, ap_msg->psmid,
-				   ap_msg->message, ap_msg->length);
+				   ap_msg->message, ap_msg->length,
+				   ap_msg->special);
 		switch (status.response_code) {
 		case AP_RESPONSE_NORMAL:
 			list_add_tail(&ap_msg->list, &ap_dev->pendingq);
@@ -1317,6 +1326,7 @@
 			ap_dev->requestq_count++;
 			ap_dev->total_request_count++;
 			return -EBUSY;
+		case AP_RESPONSE_REQ_FAC_NOT_INST:
 		case AP_RESPONSE_MESSAGE_TOO_BIG:
 			ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
 			return -EINVAL;
Index: quilt-2.6/drivers/s390/crypto/ap_bus.h
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/ap_bus.h	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/ap_bus.h	2009-11-13 16:08:15.000000000 +0100
@@ -87,6 +87,7 @@
 #define AP_RESPONSE_INDEX_TOO_BIG	0x11
 #define AP_RESPONSE_NO_FIRST_PART	0x13
 #define AP_RESPONSE_MESSAGE_TOO_BIG	0x15
+#define AP_RESPONSE_REQ_FAC_NOT_INST	0x16
 
 /*
  * Known device types
@@ -161,6 +162,7 @@
 	size_t length;			/* Message length. */
 
 	void *private;			/* ap driver private pointer. */
+	unsigned int special:1;		/* Used for special commands. */
 };
 
 #define AP_DEVICE(dt)					\
@@ -176,6 +178,7 @@
 {
 	ap_msg->psmid = 0;
 	ap_msg->length = 0;
+	ap_msg->special = 0;
 }
 
 /*
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:15.000000000 +0100
@@ -326,6 +326,11 @@
 	function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
 	memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
 
+	if (memcmp(function_code, "US", 2) == 0)
+		ap_msg->special = 1;
+	else
+		ap_msg->special = 0;
+
 	/* copy data block */
 	if (xcRB->request_data_length &&
 	    copy_from_user(req_data, xcRB->request_data_address,

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 17/52] [PATCH] zcrypt: add support for cex3 device types
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (15 preceding siblings ...)
  2009-11-13 15:08 ` [patch 16/52] [PATCH] zcrypt: special command support " Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 18/52] [PATCH] zcrypt: use definitions for cex3 Martin Schwidefsky
                   ` (35 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Felix Beck, Ralph Wuerthner, Martin Schwidefsky

[-- Attachment #1: 116-cex3-device.diff --]
[-- Type: text/plain, Size: 3704 bytes --]

From: Felix Beck <felix.beck@de.ibm.com>

This patch renames the CEX2C2 and CEX2A2 types to CEX3 device types.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/crypto/ap_bus.h        |    4 ++--
 drivers/s390/crypto/zcrypt_api.c    |    9 +++++++--
 drivers/s390/crypto/zcrypt_cex2a.c  |    2 +-
 drivers/s390/crypto/zcrypt_pcixcc.c |    2 +-
 4 files changed, 11 insertions(+), 6 deletions(-)

Index: quilt-2.6/drivers/s390/crypto/ap_bus.h
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/ap_bus.h	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/ap_bus.h	2009-11-13 16:08:15.000000000 +0100
@@ -97,8 +97,8 @@
 #define AP_DEVICE_TYPE_PCIXCC	5
 #define AP_DEVICE_TYPE_CEX2A	6
 #define AP_DEVICE_TYPE_CEX2C	7
-#define AP_DEVICE_TYPE_CEX2A2	8
-#define AP_DEVICE_TYPE_CEX2C2	9
+#define AP_DEVICE_TYPE_CEX3A	8
+#define AP_DEVICE_TYPE_CEX3C	9
 
 /*
  * AP reset flag states
Index: quilt-2.6/drivers/s390/crypto/zcrypt_api.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_api.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_api.c	2009-11-13 16:08:15.000000000 +0100
@@ -1009,6 +1009,10 @@
 		       zcrypt_count_type(ZCRYPT_CEX2C));
 	len += sprintf(resp_buff + len, "CEX2A count: %d\n",
 		       zcrypt_count_type(ZCRYPT_CEX2A));
+	len += sprintf(resp_buff + len, "CEX3C count: %d\n",
+		       zcrypt_count_type(ZCRYPT_CEX3C));
+	len += sprintf(resp_buff + len, "CEX3A count: %d\n",
+		       zcrypt_count_type(ZCRYPT_CEX3A));
 	len += sprintf(resp_buff + len, "requestq count: %d\n",
 		       zcrypt_requestq_count());
 	len += sprintf(resp_buff + len, "pendingq count: %d\n",
@@ -1017,7 +1021,7 @@
 		       atomic_read(&zcrypt_open_count));
 	zcrypt_status_mask(workarea);
 	len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
-			"4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
+			"4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A 7=CEX3C 8=CEX3A",
 			resp_buff+len, workarea, AP_DEVICES);
 	zcrypt_qdepth_mask(workarea);
 	len += sprinthx("Waiting work element counts",
@@ -1095,8 +1099,9 @@
 		 * '0' for no device, '1' for PCICA, '2' for PCICC,
 		 * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3,
 		 * '5' for CEX2C and '6' for CEX2A'
+		 * '7' for CEX3C and '8' for CEX3A
 		 */
-		if (*ptr >= '0' && *ptr <= '6')
+		if (*ptr >= '0' && *ptr <= '8')
 			j++;
 		else if (*ptr == 'd' || *ptr == 'D')
 			zcrypt_disable_card(j++);
Index: quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:15.000000000 +0100
@@ -49,7 +49,7 @@
 
 static struct ap_device_id zcrypt_cex2a_ids[] = {
 	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
-	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2A2) },
+	{ AP_DEVICE(AP_DEVICE_TYPE_CEX3A) },
 	{ /* end of list */ },
 };
 
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:15.000000000 +0100
@@ -72,7 +72,7 @@
 static struct ap_device_id zcrypt_pcixcc_ids[] = {
 	{ AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
 	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
-	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2C2) },
+	{ AP_DEVICE(AP_DEVICE_TYPE_CEX3C) },
 	{ /* end of list */ },
 };
 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 18/52] [PATCH] zcrypt: use definitions for cex3
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (16 preceding siblings ...)
  2009-11-13 15:08 ` [patch 17/52] [PATCH] zcrypt: add support for cex3 device types Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 19/52] [PATCH] zcrypt: adjust speed rating between cex2 and pcixcc Martin Schwidefsky
                   ` (34 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Felix Beck, Ralph Wuerthner, Martin Schwidefsky

[-- Attachment #1: 117-cex3-use-def.diff --]
[-- Type: text/plain, Size: 6277 bytes --]

From: Felix Beck <felix.beck@de.ibm.com>

New definitions are added for CEX3 device types. They will be set
in the according probe functions. CEX3 device types will be handled
in the same modules as CEX2 device types. In the first step they are
the same as CEX2 types, but they can be adjusted for further
characteristics of CEX3 easily.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/crypto/zcrypt_api.h    |    2 +
 drivers/s390/crypto/zcrypt_cex2a.c  |   69 +++++++++++++++++++++++-------------
 drivers/s390/crypto/zcrypt_pcixcc.c |   22 +++++++++--
 3 files changed, 66 insertions(+), 27 deletions(-)

Index: quilt-2.6/drivers/s390/crypto/zcrypt_api.h
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_api.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_api.h	2009-11-13 16:08:16.000000000 +0100
@@ -71,6 +71,8 @@
 #define ZCRYPT_PCIXCC_MCL3	4
 #define ZCRYPT_CEX2C		5
 #define ZCRYPT_CEX2A		6
+#define ZCRYPT_CEX3C		7
+#define ZCRYPT_CEX3A		8
 
 /**
  * Large random numbers are pulled in 4096 byte chunks from the crypto cards
Index: quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:16.000000000 +0100
@@ -39,13 +39,20 @@
 
 #define CEX2A_MIN_MOD_SIZE	  1	/*    8 bits	*/
 #define CEX2A_MAX_MOD_SIZE	256	/* 2048 bits	*/
+#define CEX3A_MIN_MOD_SIZE	CEX2A_MIN_MOD_SIZE
+#define CEX3A_MAX_MOD_SIZE	CEX2A_MAX_MOD_SIZE
 
 #define CEX2A_SPEED_RATING	970
+#define CEX3A_SPEED_RATING	1100
 
 #define CEX2A_MAX_MESSAGE_SIZE	0x390	/* sizeof(struct type50_crb2_msg)    */
 #define CEX2A_MAX_RESPONSE_SIZE 0x110	/* max outputdatalength + type80_hdr */
 
+#define CEX3A_MAX_MESSAGE_SIZE	CEX2A_MAX_MESSAGE_SIZE
+#define CEX3A_MAX_RESPONSE_SIZE	CEX2A_MAX_RESPONSE_SIZE
+
 #define CEX2A_CLEANUP_TIME	(15*HZ)
+#define CEX3A_CLEANUP_TIME	CEX2A_CLEANUP_TIME
 
 static struct ap_device_id zcrypt_cex2a_ids[] = {
 	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
@@ -375,31 +382,45 @@
  */
 static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
 {
-	struct zcrypt_device *zdev;
-	int rc;
+	struct zcrypt_device *zdev = NULL;
+	int rc = 0;
 
-	zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
-	if (!zdev)
-		return -ENOMEM;
-	zdev->ap_dev = ap_dev;
-	zdev->ops = &zcrypt_cex2a_ops;
-	zdev->online = 1;
-	zdev->user_space_type = ZCRYPT_CEX2A;
-	zdev->type_string = "CEX2A";
-	zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
-	zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
-	zdev->short_crt = 1;
-	zdev->speed_rating = CEX2A_SPEED_RATING;
-	ap_dev->reply = &zdev->reply;
-	ap_dev->private = zdev;
-	rc = zcrypt_device_register(zdev);
-	if (rc)
-		goto out_free;
-	return 0;
-
-out_free:
-	ap_dev->private = NULL;
-	zcrypt_device_free(zdev);
+	switch (ap_dev->device_type) {
+	case AP_DEVICE_TYPE_CEX2A:
+		zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
+		if (!zdev)
+			return -ENOMEM;
+		zdev->user_space_type = ZCRYPT_CEX2A;
+		zdev->type_string = "CEX2A";
+		zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
+		zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
+		zdev->short_crt = 1;
+		zdev->speed_rating = CEX2A_SPEED_RATING;
+		break;
+	case AP_DEVICE_TYPE_CEX3A:
+		zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE);
+		if (!zdev)
+			return -ENOMEM;
+		zdev->user_space_type = ZCRYPT_CEX3A;
+		zdev->type_string = "CEX3A";
+		zdev->min_mod_size = CEX3A_MIN_MOD_SIZE;
+		zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
+		zdev->short_crt = 1;
+		zdev->speed_rating = CEX3A_SPEED_RATING;
+		break;
+	}
+	if (zdev != NULL) {
+		zdev->ap_dev = ap_dev;
+		zdev->ops = &zcrypt_cex2a_ops;
+		zdev->online = 1;
+		ap_dev->reply = &zdev->reply;
+		ap_dev->private = zdev;
+		rc = zcrypt_device_register(zdev);
+	}
+	if (rc) {
+		ap_dev->private = NULL;
+		zcrypt_device_free(zdev);
+	}
 	return rc;
 }
 
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:15.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:16.000000000 +0100
@@ -43,10 +43,13 @@
 #define PCIXCC_MIN_MOD_SIZE	 16	/*  128 bits	*/
 #define PCIXCC_MIN_MOD_SIZE_OLD	 64	/*  512 bits	*/
 #define PCIXCC_MAX_MOD_SIZE	256	/* 2048 bits	*/
+#define CEX3C_MIN_MOD_SIZE	PCIXCC_MIN_MOD_SIZE
+#define CEX3C_MAX_MOD_SIZE	PCIXCC_MAX_MOD_SIZE
 
 #define PCIXCC_MCL2_SPEED_RATING	7870	/* FIXME: needs finetuning */
 #define PCIXCC_MCL3_SPEED_RATING	7870
 #define CEX2C_SPEED_RATING		8540
+#define CEX3C_SPEED_RATING		10000	/* FIXME: needs finetuning */
 
 #define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c  /* max size type6 v2 crt message */
 #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply	    */
@@ -1026,14 +1029,15 @@
 static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
 {
 	struct zcrypt_device *zdev;
-	int rc;
+	int rc = 0;
 
 	zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
 	if (!zdev)
 		return -ENOMEM;
 	zdev->ap_dev = ap_dev;
 	zdev->online = 1;
-	if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {
+	switch (ap_dev->device_type) {
+	case AP_DEVICE_TYPE_PCIXCC:
 		rc = zcrypt_pcixcc_mcl(ap_dev);
 		if (rc < 0) {
 			zcrypt_device_free(zdev);
@@ -1051,13 +1055,25 @@
 			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
 			zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
 		}
-	} else {
+		break;
+	case AP_DEVICE_TYPE_CEX2C:
 		zdev->user_space_type = ZCRYPT_CEX2C;
 		zdev->type_string = "CEX2C";
 		zdev->speed_rating = CEX2C_SPEED_RATING;
 		zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
 		zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+		break;
+	case AP_DEVICE_TYPE_CEX3C:
+		zdev->user_space_type = ZCRYPT_CEX3C;
+		zdev->type_string = "CEX3C";
+		zdev->speed_rating = CEX3C_SPEED_RATING;
+		zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
+		zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
+		break;
+	default:
+		goto out_free;
 	}
+
 	rc = zcrypt_pcixcc_rng_supported(ap_dev);
 	if (rc < 0) {
 		zcrypt_device_free(zdev);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 19/52] [PATCH] zcrypt: adjust speed rating between cex2 and pcixcc
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (17 preceding siblings ...)
  2009-11-13 15:08 ` [patch 18/52] [PATCH] zcrypt: use definitions for cex3 Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 20/52] [PATCH] zcrypt: adjust speed rating of cex3 adapters Martin Schwidefsky
                   ` (33 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Felix Beck, Martin Schwidefsky

[-- Attachment #1: 118-zcrypt-speed-cex2c.diff --]
[-- Type: text/plain, Size: 1220 bytes --]

From: Felix Beck <felix.beck@de.ibm.com>

Cards with lower speed rating are prefered. Thus change adjust the
speed rating of cex2c adapters to be prefered before pcixcc, although
they should not appear in the same machine anyway.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/crypto/zcrypt_pcixcc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:16.000000000 +0100
@@ -46,9 +46,9 @@
 #define CEX3C_MIN_MOD_SIZE	PCIXCC_MIN_MOD_SIZE
 #define CEX3C_MAX_MOD_SIZE	PCIXCC_MAX_MOD_SIZE
 
-#define PCIXCC_MCL2_SPEED_RATING	7870	/* FIXME: needs finetuning */
+#define PCIXCC_MCL2_SPEED_RATING	7870
 #define PCIXCC_MCL3_SPEED_RATING	7870
-#define CEX2C_SPEED_RATING		8540
+#define CEX2C_SPEED_RATING		7000
 #define CEX3C_SPEED_RATING		10000	/* FIXME: needs finetuning */
 
 #define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c  /* max size type6 v2 crt message */

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 20/52] [PATCH] zcrypt: adjust speed rating of cex3 adapters
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (18 preceding siblings ...)
  2009-11-13 15:08 ` [patch 19/52] [PATCH] zcrypt: adjust speed rating between cex2 and pcixcc Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 21/52] [PATCH] dasd: enable prefix independent of pav support Martin Schwidefsky
                   ` (32 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Felix Beck, Martin Schwidefsky

[-- Attachment #1: 119-zcrypt-speed-cex3.diff --]
[-- Type: text/plain, Size: 1743 bytes --]

From: Felix Beck <felix.beck@de.ibm.com>

Cex3 needs a lower speed rating. Otherwise cex2 adapters will be
prefered.

Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/crypto/zcrypt_cex2a.c  |    2 +-
 drivers/s390/crypto/zcrypt_pcixcc.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

Index: quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_cex2a.c	2009-11-13 16:08:16.000000000 +0100
@@ -43,7 +43,7 @@
 #define CEX3A_MAX_MOD_SIZE	CEX2A_MAX_MOD_SIZE
 
 #define CEX2A_SPEED_RATING	970
-#define CEX3A_SPEED_RATING	1100
+#define CEX3A_SPEED_RATING	900 /* Fixme: Needs finetuning */
 
 #define CEX2A_MAX_MESSAGE_SIZE	0x390	/* sizeof(struct type50_crb2_msg)    */
 #define CEX2A_MAX_RESPONSE_SIZE 0x110	/* max outputdatalength + type80_hdr */
Index: quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/crypto/zcrypt_pcixcc.c	2009-11-13 16:08:16.000000000 +0100
@@ -49,7 +49,7 @@
 #define PCIXCC_MCL2_SPEED_RATING	7870
 #define PCIXCC_MCL3_SPEED_RATING	7870
 #define CEX2C_SPEED_RATING		7000
-#define CEX3C_SPEED_RATING		10000	/* FIXME: needs finetuning */
+#define CEX3C_SPEED_RATING		6500	/* FIXME: needs finetuning */
 
 #define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c  /* max size type6 v2 crt message */
 #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply	    */

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 21/52] [PATCH] dasd: enable prefix independent of pav support
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (19 preceding siblings ...)
  2009-11-13 15:08 ` [patch 20/52] [PATCH] zcrypt: adjust speed rating of cex3 adapters Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 22/52] [PATCH] dasd: improve error recovery for internal I/O Martin Schwidefsky
                   ` (31 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Stefan Weinhuber, Martin Schwidefsky

[-- Attachment #1: 120-dasd-enable-prefix.diff --]
[-- Type: text/plain, Size: 1206 bytes --]

From: Stefan Weinhuber <wein@de.ibm.com>

The DASD device driver needs to explicitly enable the prefix command
on the storage server, before it can be used. Originally we enabled
this command along with others only if we wanted to support PAV.
However, today we require this command for other features like
High Performance FICON as well, so we need to always enable prefix.

Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/block/dasd_eckd.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: quilt-2.6/drivers/s390/block/dasd_eckd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:14.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:16.000000000 +0100
@@ -1011,9 +1011,9 @@
 	}
 	psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
 	psf_ssc_data->order = PSF_ORDER_SSC;
-	psf_ssc_data->suborder = 0x40;
+	psf_ssc_data->suborder = 0xc0;
 	if (enable_pav) {
-		psf_ssc_data->suborder |= 0x88;
+		psf_ssc_data->suborder |= 0x08;
 		psf_ssc_data->reserved[0] = 0x88;
 	}
 	ccw = cqr->cpaddr;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 22/52] [PATCH] dasd: improve error recovery for internal I/O
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (20 preceding siblings ...)
  2009-11-13 15:08 ` [patch 21/52] [PATCH] dasd: enable prefix independent of pav support Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 23/52] [PATCH] dasd: remove strings from s390dbf Martin Schwidefsky
                   ` (30 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Stefan Weinhuber, Martin Schwidefsky

[-- Attachment #1: 121-dasd-internel-io-errors.diff --]
[-- Type: text/plain, Size: 24427 bytes --]

From: Stefan Weinhuber <wein@de.ibm.com>

Most of the error conditions reported by a FICON storage server
indicate situations which can be recovered. Sometimes the host just
needs to retry an I/O request, but sometimes the recovery
is more complex and requires the device driver to wait, choose
a different path, etc.

The DASD device driver has a fully featured error recovery
for normal block layer I/O, but not for internal I/O request which
are for example used during the device bring up.
This can lead to situations where the IPL of a system fails because
DASD devices are not properly recognized.
This patch will extend the internal I/O handling to use the existing
error recovery procedures.

Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/block/dasd.c          |  207 +++++++++++++++++++++++++++----------
 drivers/s390/block/dasd_3990_erp.c |   46 +++++---
 drivers/s390/block/dasd_alias.c    |   15 +-
 drivers/s390/block/dasd_eckd.c     |   72 +++++++++---
 drivers/s390/block/dasd_int.h      |    3 
 drivers/s390/block/dasd_ioctl.c    |    4 
 6 files changed, 253 insertions(+), 94 deletions(-)

Index: quilt-2.6/drivers/s390/block/dasd_3990_erp.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_3990_erp.c	2009-11-13 16:08:14.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_3990_erp.c	2009-11-13 16:08:16.000000000 +0100
@@ -69,8 +69,7 @@
  *   processing until the started timer has expired or an related
  *   interrupt was received.
  */
-static void
-dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
+static void dasd_3990_erp_block_queue(struct dasd_ccw_req *erp, int expires)
 {
 
 	struct dasd_device *device = erp->startdev;
@@ -80,10 +79,13 @@
 		    "blocking request queue for %is", expires/HZ);
 
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->stopped |= DASD_STOPPED_PENDING;
+	dasd_device_set_stop_bits(device, DASD_STOPPED_PENDING);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	erp->status = DASD_CQR_FILLED;
-	dasd_block_set_timer(device->block, expires);
+	if (erp->block)
+		dasd_block_set_timer(erp->block, expires);
+	else
+		dasd_device_set_timer(device, expires);
 }
 
 /*
@@ -242,9 +244,13 @@
  * DESCRIPTION
  *   Setup ERP to do the ERP action 1 (see Reference manual).
  *   Repeat the operation on a different channel path.
- *   If all alternate paths have been tried, the request is posted with a
- *   permanent error.
- *   Note: duplex handling is not implemented (yet).
+ *   As deviation from the recommended recovery action, we reset the path mask
+ *   after we have tried each path and go through all paths a second time.
+ *   This will cover situations where only one path at a time is actually down,
+ *   but all paths fail and recover just with the same sequence and timing as
+ *   we try to use them (flapping links).
+ *   If all alternate paths have been tried twice, the request is posted with
+ *   a permanent error.
  *
  *  PARAMETER
  *   erp		pointer to the current ERP
@@ -253,17 +259,25 @@
  *   erp		pointer to the ERP
  *
  */
-static struct dasd_ccw_req *
-dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
+static struct dasd_ccw_req *dasd_3990_erp_action_1_sec(struct dasd_ccw_req *erp)
 {
+	erp->function = dasd_3990_erp_action_1_sec;
+	dasd_3990_erp_alternate_path(erp);
+	return erp;
+}
 
+static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp)
+{
 	erp->function = dasd_3990_erp_action_1;
-
 	dasd_3990_erp_alternate_path(erp);
-
+	if (erp->status == DASD_CQR_FAILED) {
+		erp->status = DASD_CQR_FILLED;
+		erp->retries = 10;
+		erp->lpm = LPM_ANYPATH;
+		erp->function = dasd_3990_erp_action_1_sec;
+	}
 	return erp;
-
-}				/* end dasd_3990_erp_action_1 */
+}				/* end dasd_3990_erp_action_1(b) */
 
 /*
  * DASD_3990_ERP_ACTION_4
@@ -2294,6 +2308,7 @@
 		return cqr;
 	}
 
+	ccw = cqr->cpaddr;
 	if (cqr->cpmode == 1) {
 		/* make a shallow copy of the original tcw but set new tsb */
 		erp->cpmode = 1;
@@ -2302,6 +2317,9 @@
 		tsb = (struct tsb *) &tcw[1];
 		*tcw = *((struct tcw *)cqr->cpaddr);
 		tcw->tsb = (long)tsb;
+	} else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) {
+		/* PSF cannot be chained from NOOP/TIC */
+		erp->cpaddr = cqr->cpaddr;
 	} else {
 		/* initialize request with default TIC to current ERP/CQR */
 		ccw = erp->cpaddr;
@@ -2486,6 +2504,8 @@
 
 		erp = dasd_3990_erp_action_1(erp);
 
+	} else if (erp->function == dasd_3990_erp_action_1_sec) {
+		erp = dasd_3990_erp_action_1_sec(erp);
 	} else if (erp->function == dasd_3990_erp_action_5) {
 
 		/* retries have not been successful */
Index: quilt-2.6/drivers/s390/block/dasd_alias.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_alias.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_alias.c	2009-11-13 16:08:16.000000000 +0100
@@ -755,11 +755,11 @@
 {
 	/* If pos == device then device is already locked! */
 	if (pos == device) {
-		pos->stopped |= DASD_STOPPED_SU;
+		dasd_device_set_stop_bits(pos, DASD_STOPPED_SU);
 		return;
 	}
 	spin_lock(get_ccwdev_lock(pos->cdev));
-	pos->stopped |= DASD_STOPPED_SU;
+	dasd_device_set_stop_bits(pos, DASD_STOPPED_SU);
 	spin_unlock(get_ccwdev_lock(pos->cdev));
 }
 
@@ -793,26 +793,26 @@
 
 	list_for_each_entry(device, &lcu->active_devices, alias_list) {
 		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-		device->stopped &= ~DASD_STOPPED_SU;
+		dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
 		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	}
 
 	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
 		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-		device->stopped &= ~DASD_STOPPED_SU;
+		dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
 		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	}
 
 	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
 		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
 			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-			device->stopped &= ~DASD_STOPPED_SU;
+			dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
 			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
 					       flags);
 		}
 		list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
 			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-			device->stopped &= ~DASD_STOPPED_SU;
+			dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
 			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
 					       flags);
 		}
@@ -836,7 +836,8 @@
 
 	/* 2. reset summary unit check */
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
+	dasd_device_remove_stop_bits(device,
+				     (DASD_STOPPED_SU | DASD_STOPPED_PENDING));
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	reset_summary_unit_check(lcu, device, suc_data->reason);
 
Index: quilt-2.6/drivers/s390/block/dasd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd.c	2009-11-13 16:08:14.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd.c	2009-11-13 16:08:16.000000000 +0100
@@ -63,6 +63,7 @@
 static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
 static void dasd_device_timeout(unsigned long);
 static void dasd_block_timeout(unsigned long);
+static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *);
 
 /*
  * SECTION: Operations on the device structure.
@@ -959,7 +960,7 @@
 	device = (struct dasd_device *) ptr;
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	/* re-activate request queue */
-        device->stopped &= ~DASD_STOPPED_PENDING;
+	dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	dasd_schedule_device_bh(device);
 }
@@ -1022,7 +1023,7 @@
 	/* First of all start sense subsystem status request. */
 	dasd_eer_snss(device);
 
-	device->stopped &= ~DASD_STOPPED_PENDING;
+	dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING);
 	dasd_schedule_device_bh(device);
 	if (device->block)
 		dasd_schedule_block_bh(device->block);
@@ -1404,6 +1405,20 @@
 	tasklet_hi_schedule(&device->tasklet);
 }
 
+void dasd_device_set_stop_bits(struct dasd_device *device, int bits)
+{
+	device->stopped |= bits;
+}
+EXPORT_SYMBOL_GPL(dasd_device_set_stop_bits);
+
+void dasd_device_remove_stop_bits(struct dasd_device *device, int bits)
+{
+	device->stopped &= ~bits;
+	if (!device->stopped)
+		wake_up(&generic_waitq);
+}
+EXPORT_SYMBOL_GPL(dasd_device_remove_stop_bits);
+
 /*
  * Queue a request to the head of the device ccw_queue.
  * Start the I/O if possible.
@@ -1464,58 +1479,135 @@
 }
 
 /*
- * Queue a request to the tail of the device ccw_queue and wait for
- * it's completion.
+ * checks if error recovery is necessary, returns 1 if yes, 0 otherwise.
  */
-int dasd_sleep_on(struct dasd_ccw_req *cqr)
+static int __dasd_sleep_on_erp(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
-	int rc;
+	dasd_erp_fn_t erp_fn;
 
+	if (cqr->status == DASD_CQR_FILLED)
+		return 0;
 	device = cqr->startdev;
+	if (test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) {
+		if (cqr->status == DASD_CQR_TERMINATED) {
+			device->discipline->handle_terminated_request(cqr);
+			return 1;
+		}
+		if (cqr->status == DASD_CQR_NEED_ERP) {
+			erp_fn = device->discipline->erp_action(cqr);
+			erp_fn(cqr);
+			return 1;
+		}
+		if (cqr->status == DASD_CQR_FAILED)
+			dasd_log_sense(cqr, &cqr->irb);
+		if (cqr->refers) {
+			__dasd_process_erp(device, cqr);
+			return 1;
+		}
+	}
+	return 0;
+}
 
-	cqr->callback = dasd_wakeup_cb;
-	cqr->callback_data = (void *) &generic_waitq;
-	dasd_add_request_tail(cqr);
-	wait_event(generic_waitq, _wait_for_wakeup(cqr));
+static int __dasd_sleep_on_loop_condition(struct dasd_ccw_req *cqr)
+{
+	if (test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) {
+		if (cqr->refers) /* erp is not done yet */
+			return 1;
+		return ((cqr->status != DASD_CQR_DONE) &&
+			(cqr->status != DASD_CQR_FAILED));
+	} else
+		return (cqr->status == DASD_CQR_FILLED);
+}
 
-	if (cqr->status == DASD_CQR_DONE)
+static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
+{
+	struct dasd_device *device;
+	int rc;
+	struct list_head ccw_queue;
+	struct dasd_ccw_req *cqr;
+
+	INIT_LIST_HEAD(&ccw_queue);
+	maincqr->status = DASD_CQR_FILLED;
+	device = maincqr->startdev;
+	list_add(&maincqr->blocklist, &ccw_queue);
+	for (cqr = maincqr;  __dasd_sleep_on_loop_condition(cqr);
+	     cqr = list_first_entry(&ccw_queue,
+				    struct dasd_ccw_req, blocklist)) {
+
+		if (__dasd_sleep_on_erp(cqr))
+			continue;
+		if (cqr->status != DASD_CQR_FILLED) /* could be failed */
+			continue;
+
+		/* Non-temporary stop condition will trigger fail fast */
+		if (device->stopped & ~DASD_STOPPED_PENDING &&
+		    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+		    (!dasd_eer_enabled(device))) {
+			cqr->status = DASD_CQR_FAILED;
+			continue;
+		}
+
+		/* Don't try to start requests if device is stopped */
+		if (interruptible) {
+			rc = wait_event_interruptible(
+				generic_waitq, !(device->stopped));
+			if (rc == -ERESTARTSYS) {
+				cqr->status = DASD_CQR_FAILED;
+				maincqr->intrc = rc;
+				continue;
+			}
+		} else
+			wait_event(generic_waitq, !(device->stopped));
+
+		cqr->callback = dasd_wakeup_cb;
+		cqr->callback_data = (void *) &generic_waitq;
+		dasd_add_request_tail(cqr);
+		if (interruptible) {
+			rc = wait_event_interruptible(
+				generic_waitq, _wait_for_wakeup(cqr));
+			if (rc == -ERESTARTSYS) {
+				dasd_cancel_req(cqr);
+				/* wait (non-interruptible) for final status */
+				wait_event(generic_waitq,
+					   _wait_for_wakeup(cqr));
+				cqr->status = DASD_CQR_FAILED;
+				maincqr->intrc = rc;
+				continue;
+			}
+		} else
+			wait_event(generic_waitq, _wait_for_wakeup(cqr));
+	}
+
+	maincqr->endclk = get_clock();
+	if ((maincqr->status != DASD_CQR_DONE) &&
+	    (maincqr->intrc != -ERESTARTSYS))
+		dasd_log_sense(maincqr, &maincqr->irb);
+	if (maincqr->status == DASD_CQR_DONE)
 		rc = 0;
-	else if (cqr->intrc)
-		rc = cqr->intrc;
+	else if (maincqr->intrc)
+		rc = maincqr->intrc;
 	else
 		rc = -EIO;
 	return rc;
 }
 
 /*
+ * Queue a request to the tail of the device ccw_queue and wait for
+ * it's completion.
+ */
+int dasd_sleep_on(struct dasd_ccw_req *cqr)
+{
+	return _dasd_sleep_on(cqr, 0);
+}
+
+/*
  * Queue a request to the tail of the device ccw_queue and wait
  * interruptible for it's completion.
  */
 int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device;
-	int rc;
-
-	device = cqr->startdev;
-	cqr->callback = dasd_wakeup_cb;
-	cqr->callback_data = (void *) &generic_waitq;
-	dasd_add_request_tail(cqr);
-	rc = wait_event_interruptible(generic_waitq, _wait_for_wakeup(cqr));
-	if (rc == -ERESTARTSYS) {
-		dasd_cancel_req(cqr);
-		/* wait (non-interruptible) for final status */
-		wait_event(generic_waitq, _wait_for_wakeup(cqr));
-		cqr->intrc = rc;
-	}
-
-	if (cqr->status == DASD_CQR_DONE)
-		rc = 0;
-	else if (cqr->intrc)
-		rc = cqr->intrc;
-	else
-		rc = -EIO;
-	return rc;
+	return _dasd_sleep_on(cqr, 1);
 }
 
 /*
@@ -1629,7 +1721,7 @@
 	block = (struct dasd_block *) ptr;
 	spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
 	/* re-activate request queue */
-	block->base->stopped &= ~DASD_STOPPED_PENDING;
+	dasd_device_remove_stop_bits(block->base, DASD_STOPPED_PENDING);
 	spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
 	dasd_schedule_block_bh(block);
 }
@@ -1656,11 +1748,10 @@
 /*
  * Process finished error recovery ccw.
  */
-static inline void __dasd_block_process_erp(struct dasd_block *block,
-					    struct dasd_ccw_req *cqr)
+static void __dasd_process_erp(struct dasd_device *device,
+			       struct dasd_ccw_req *cqr)
 {
 	dasd_erp_fn_t erp_fn;
-	struct dasd_device *device = block->base;
 
 	if (cqr->status == DASD_CQR_DONE)
 		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
@@ -1724,9 +1815,12 @@
 				 */
 				if (!list_empty(&block->ccw_queue))
 					break;
-				spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
-				basedev->stopped |= DASD_STOPPED_PENDING;
-				spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
+				spin_lock_irqsave(
+					get_ccwdev_lock(basedev->cdev), flags);
+				dasd_device_set_stop_bits(basedev,
+							  DASD_STOPPED_PENDING);
+				spin_unlock_irqrestore(
+					get_ccwdev_lock(basedev->cdev), flags);
 				dasd_block_set_timer(block, HZ/2);
 				break;
 			}
@@ -1812,7 +1906,7 @@
 			cqr->status = DASD_CQR_FILLED;
 			cqr->retries = 255;
 			spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-			base->stopped |= DASD_STOPPED_QUIESCE;
+			dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
 			spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
 					       flags);
 			goto restart;
@@ -1820,7 +1914,7 @@
 
 		/* Process finished ERP request. */
 		if (cqr->refers) {
-			__dasd_block_process_erp(block, cqr);
+			__dasd_process_erp(base, cqr);
 			goto restart;
 		}
 
@@ -1951,7 +2045,7 @@
 		/* Process finished ERP request. */
 		if (cqr->refers) {
 			spin_lock_bh(&block->queue_lock);
-			__dasd_block_process_erp(block, cqr);
+			__dasd_process_erp(block->base, cqr);
 			spin_unlock_bh(&block->queue_lock);
 			/* restart list_for_xx loop since dasd_process_erp
 			 * might remove multiple elements */
@@ -2417,16 +2511,16 @@
 				cqr->status = DASD_CQR_QUEUED;
 				cqr->retries++;
 			}
-		device->stopped |= DASD_STOPPED_DC_WAIT;
+		dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT);
 		dasd_device_clear_timer(device);
 		dasd_schedule_device_bh(device);
 		ret = 1;
 		break;
 	case CIO_OPER:
 		/* FIXME: add a sanity check. */
-		device->stopped &= ~DASD_STOPPED_DC_WAIT;
+		dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT);
 		if (device->stopped & DASD_UNRESUMED_PM) {
-			device->stopped &= ~DASD_UNRESUMED_PM;
+			dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM);
 			dasd_restore_device(device);
 			ret = 1;
 			break;
@@ -2451,7 +2545,7 @@
 	if (IS_ERR(device))
 		return PTR_ERR(device);
 	/* disallow new I/O  */
-	device->stopped |= DASD_STOPPED_PM;
+	dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
 	/* clear active requests */
 	INIT_LIST_HEAD(&freeze_queue);
 	spin_lock_irq(get_ccwdev_lock(cdev));
@@ -2503,14 +2597,18 @@
 		return PTR_ERR(device);
 
 	/* allow new IO again */
-	device->stopped &= ~DASD_STOPPED_PM;
-	device->stopped &= ~DASD_UNRESUMED_PM;
+	dasd_device_remove_stop_bits(device,
+				     (DASD_STOPPED_PM | DASD_UNRESUMED_PM));
 
 	dasd_schedule_device_bh(device);
 
-	if (device->discipline->restore)
+	/*
+	 * call discipline restore function
+	 * if device is stopped do nothing e.g. for disconnected devices
+	 */
+	if (device->discipline->restore && !(device->stopped))
 		rc = device->discipline->restore(device);
-	if (rc)
+	if (rc || device->stopped)
 		/*
 		 * if the resume failed for the DASD we put it in
 		 * an UNRESUMED stop state
@@ -2560,8 +2658,7 @@
 	cqr->startdev = device;
 	cqr->memdev = device;
 	cqr->expires = 10*HZ;
-	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-	cqr->retries = 2;
+	cqr->retries = 256;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	return cqr;
Index: quilt-2.6/drivers/s390/block/dasd_eckd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:16.000000000 +0100
@@ -77,6 +77,11 @@
 
 static struct ccw_driver dasd_eckd_driver; /* see below */
 
+#define INIT_CQR_OK 0
+#define INIT_CQR_UNFORMATTED 1
+#define INIT_CQR_ERROR 2
+
+
 /* initial attempt at a probe function. this can be simplified once
  * the other detection code is gone */
 static int
@@ -748,8 +753,7 @@
 	cqr->block = NULL;
 	cqr->expires = 10*HZ;
 	cqr->lpm = lpm;
-	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-	cqr->retries = 2;
+	cqr->retries = 256;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	return cqr;
@@ -948,8 +952,7 @@
 	cqr->startdev = device;
 	cqr->memdev = device;
 	cqr->block = NULL;
-	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-	cqr->retries = 5;
+	cqr->retries = 256;
 	cqr->expires = 10 * HZ;
 
 	/* Prepare for Read Subsystem Data */
@@ -1024,6 +1027,7 @@
 	cqr->startdev = device;
 	cqr->memdev = device;
 	cqr->block = NULL;
+	cqr->retries = 256;
 	cqr->expires = 10*HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
@@ -1067,6 +1071,7 @@
 	else
 		enable_pav = 1;
 	rc = dasd_eckd_psf_ssc(device, enable_pav);
+
 	/* may be requested feature is not available on server,
 	 * therefore just report error and go ahead */
 	private = (struct dasd_eckd_private *) device->private;
@@ -1255,12 +1260,29 @@
 	cqr->block = NULL;
 	cqr->startdev = device;
 	cqr->memdev = device;
-	cqr->retries = 0;
+	cqr->retries = 255;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	return cqr;
 }
 
+/* differentiate between 'no record found' and any other error */
+static int dasd_eckd_analysis_evaluation(struct dasd_ccw_req *init_cqr)
+{
+	char *sense;
+	if (init_cqr->status == DASD_CQR_DONE)
+		return INIT_CQR_OK;
+	else if (init_cqr->status == DASD_CQR_NEED_ERP ||
+		 init_cqr->status == DASD_CQR_FAILED) {
+		sense = dasd_get_sense(&init_cqr->irb);
+		if (sense && (sense[1] & SNS1_NO_REC_FOUND))
+			return INIT_CQR_UNFORMATTED;
+		else
+			return INIT_CQR_ERROR;
+	} else
+		return INIT_CQR_ERROR;
+}
+
 /*
  * This is the callback function for the init_analysis cqr. It saves
  * the status of the initial analysis ccw before it frees it and kicks
@@ -1268,21 +1290,20 @@
  * dasd_eckd_do_analysis again (if the devices has not been marked
  * for deletion in the meantime).
  */
-static void
-dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
+static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr,
+					void *data)
 {
 	struct dasd_eckd_private *private;
 	struct dasd_device *device;
 
 	device = init_cqr->startdev;
 	private = (struct dasd_eckd_private *) device->private;
-	private->init_cqr_status = init_cqr->status;
+	private->init_cqr_status = dasd_eckd_analysis_evaluation(init_cqr);
 	dasd_sfree_request(init_cqr, device);
 	dasd_kick_device(device);
 }
 
-static int
-dasd_eckd_start_analysis(struct dasd_block *block)
+static int dasd_eckd_start_analysis(struct dasd_block *block)
 {
 	struct dasd_eckd_private *private;
 	struct dasd_ccw_req *init_cqr;
@@ -1294,27 +1315,44 @@
 	init_cqr->callback = dasd_eckd_analysis_callback;
 	init_cqr->callback_data = NULL;
 	init_cqr->expires = 5*HZ;
+	/* first try without ERP, so we can later handle unformatted
+	 * devices as special case
+	 */
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &init_cqr->flags);
+	init_cqr->retries = 0;
 	dasd_add_request_head(init_cqr);
 	return -EAGAIN;
 }
 
-static int
-dasd_eckd_end_analysis(struct dasd_block *block)
+static int dasd_eckd_end_analysis(struct dasd_block *block)
 {
 	struct dasd_device *device;
 	struct dasd_eckd_private *private;
 	struct eckd_count *count_area;
 	unsigned int sb, blk_per_trk;
 	int status, i;
+	struct dasd_ccw_req *init_cqr;
 
 	device = block->base;
 	private = (struct dasd_eckd_private *) device->private;
 	status = private->init_cqr_status;
 	private->init_cqr_status = -1;
-	if (status != DASD_CQR_DONE) {
-		dev_warn(&device->cdev->dev,
-			    "The DASD is not formatted\n");
+	if (status == INIT_CQR_ERROR) {
+		/* try again, this time with full ERP */
+		init_cqr = dasd_eckd_analysis_ccw(device);
+		dasd_sleep_on(init_cqr);
+		status = dasd_eckd_analysis_evaluation(init_cqr);
+		dasd_sfree_request(init_cqr, device);
+	}
+
+	if (status == INIT_CQR_UNFORMATTED) {
+		dev_warn(&device->cdev->dev, "The DASD is not formatted\n");
 		return -EMEDIUMTYPE;
+	} else if (status == INIT_CQR_ERROR) {
+		dev_err(&device->cdev->dev,
+			"Detecting the DASD disk layout failed because "
+			"of an I/O error\n");
+		return -EIO;
 	}
 
 	private->uses_cdl = 1;
@@ -1606,8 +1644,7 @@
 	}
 	fcp->startdev = device;
 	fcp->memdev = device;
-	clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
-	fcp->retries = 5;	/* set retry counter to enable default ERP */
+	fcp->retries = 256;
 	fcp->buildclk = get_clock();
 	fcp->status = DASD_CQR_FILLED;
 	return fcp;
@@ -2689,6 +2726,7 @@
 	cqr->startdev = device;
 	cqr->memdev = device;
 	cqr->retries = 0;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	cqr->expires = 10 * HZ;
 
 	/* Prepare for Read Subsystem Data */
Index: quilt-2.6/drivers/s390/block/dasd_int.h
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_int.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_int.h	2009-11-13 16:08:16.000000000 +0100
@@ -595,6 +595,9 @@
 int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
 char *dasd_get_sense(struct irb *);
 
+void dasd_device_set_stop_bits(struct dasd_device *, int);
+void dasd_device_remove_stop_bits(struct dasd_device *, int);
+
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
 extern int dasd_probeonly;
Index: quilt-2.6/drivers/s390/block/dasd_ioctl.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_ioctl.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_ioctl.c	2009-11-13 16:08:16.000000000 +0100
@@ -101,7 +101,7 @@
 	pr_info("%s: The DASD has been put in the quiesce "
 		"state\n", dev_name(&base->cdev->dev));
 	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-	base->stopped |= DASD_STOPPED_QUIESCE;
+	dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
 	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 	return 0;
 }
@@ -122,7 +122,7 @@
 	pr_info("%s: I/O operations have been resumed "
 		"on the DASD\n", dev_name(&base->cdev->dev));
 	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-	base->stopped &= ~DASD_STOPPED_QUIESCE;
+	dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE);
 	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 
 	dasd_schedule_block_bh(block);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 23/52] [PATCH] dasd: remove strings from s390dbf
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (21 preceding siblings ...)
  2009-11-13 15:08 ` [patch 22/52] [PATCH] dasd: improve error recovery for internal I/O Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 24/52] [PATCH] s390: use change recording override for kernel mapping Martin Schwidefsky
                   ` (29 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Stefan Haberland, Martin Schwidefsky

[-- Attachment #1: 122-dasd-s390dbf-strings.diff --]
[-- Type: text/plain, Size: 7804 bytes --]

From: Stefan Haberland <stefan.haberland@de.ibm.com>

Remove strings from s390 debugfeature entries that could lead to a
crash when the data is read from dbf because the strings do not exist
any more.

Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/block/dasd.c      |   22 ++++++++++----------
 drivers/s390/block/dasd_eckd.c |   44 +++++++++++++++++------------------------
 drivers/s390/block/dasd_fba.c  |   10 +++------
 drivers/s390/block/dasd_int.h  |   10 +++++++++
 4 files changed, 44 insertions(+), 42 deletions(-)

Index: quilt-2.6/drivers/s390/block/dasd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd.c	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd.c	2009-11-13 16:08:17.000000000 +0100
@@ -994,10 +994,9 @@
 		return;
 	cqr = (struct dasd_ccw_req *) intparm;
 	if (cqr->status != DASD_CQR_IN_IO) {
-		DBF_EVENT(DBF_DEBUG,
-			"invalid status in handle_killed_request: "
-			"bus_id %s, status %02x",
-			dev_name(&cdev->dev), cqr->status);
+		DBF_EVENT_DEVID(DBF_DEBUG, cdev,
+				"invalid status in handle_killed_request: "
+				"%02x", cqr->status);
 		return;
 	}
 
@@ -1045,12 +1044,13 @@
 		case -EIO:
 			break;
 		case -ETIMEDOUT:
-			DBF_EVENT(DBF_WARNING, "%s(%s): request timed out\n",
-			       __func__, dev_name(&cdev->dev));
+			DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
+					"request timed out\n", __func__);
 			break;
 		default:
-			DBF_EVENT(DBF_WARNING, "%s(%s): unknown error %ld\n",
-			       __func__, dev_name(&cdev->dev), PTR_ERR(irb));
+			DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
+					"unknown error %ld\n", __func__,
+					PTR_ERR(irb));
 		}
 		dasd_handle_killed_request(cdev, intparm);
 		return;
@@ -2310,9 +2310,9 @@
 	}
 	ret = dasd_add_sysfs_files(cdev);
 	if (ret) {
-		DBF_EVENT(DBF_WARNING,
-		       "dasd_generic_probe: could not add sysfs entries "
-		       "for %s\n", dev_name(&cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s",
+				"dasd_generic_probe: could not add "
+				"sysfs entries");
 		return ret;
 	}
 	cdev->handler = &dasd_int_handler;
Index: quilt-2.6/drivers/s390/block/dasd_eckd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:17.000000000 +0100
@@ -92,9 +92,9 @@
 	/* set ECKD specific ccw-device options */
 	ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
 	if (ret) {
-		DBF_EVENT(DBF_WARNING,
-		       "dasd_eckd_probe: could not set ccw-device options "
-		       "for %s\n", dev_name(&cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s",
+				"dasd_eckd_probe: could not set "
+				"ccw-device options");
 		return ret;
 	}
 	ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
@@ -888,16 +888,15 @@
 			rc = dasd_eckd_read_conf_lpm(device, &conf_data,
 						     &conf_len, lpm);
 			if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */
-				DBF_EVENT(DBF_WARNING,
+				DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
 					  "Read configuration data returned "
-					  "error %d for device: %s", rc,
-					  dev_name(&device->cdev->dev));
+					  "error %d", rc);
 				return rc;
 			}
 			if (conf_data == NULL) {
-				DBF_EVENT(DBF_WARNING, "No configuration "
-					  "data retrieved for device: %s",
-					  dev_name(&device->cdev->dev));
+				DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+						"No configuration data "
+						"retrieved");
 				continue;	/* no error */
 			}
 			/* save first valid configuration data */
@@ -944,9 +943,8 @@
 				    sizeof(struct dasd_rssd_features)),
 				   device);
 	if (IS_ERR(cqr)) {
-		DBF_EVENT(DBF_WARNING, "Could not allocate initialization "
-			  "request for device: %s",
-			  dev_name(&device->cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", "Could not "
+				"allocate initialization request");
 		return PTR_ERR(cqr);
 	}
 	cqr->startdev = device;
@@ -1075,10 +1073,8 @@
 	/* may be requested feature is not available on server,
 	 * therefore just report error and go ahead */
 	private = (struct dasd_eckd_private *) device->private;
-	DBF_EVENT(DBF_WARNING, "PSF-SSC on storage subsystem %s.%s.%04x "
-		  "returned rc=%d for device: %s",
-		  private->uid.vendor, private->uid.serial,
-		  private->uid.ssid, rc, dev_name(&device->cdev->dev));
+	DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
+			"returned rc=%d", private->uid.ssid, rc);
 	/* RE-Read Configuration Data */
 	return dasd_eckd_read_conf(device);
 }
@@ -1127,9 +1123,9 @@
 	if (private->uid.type == UA_BASE_DEVICE) {
 		block = dasd_alloc_block();
 		if (IS_ERR(block)) {
-			DBF_EVENT(DBF_WARNING, "could not allocate dasd "
-				  "block structure for device: %s",
-				  dev_name(&device->cdev->dev));
+			DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+					"could not allocate dasd "
+					"block structure");
 			rc = PTR_ERR(block);
 			goto out_err1;
 		}
@@ -1157,9 +1153,8 @@
 	rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
 					 &private->rdc_data, 64);
 	if (rc) {
-		DBF_EVENT(DBF_WARNING,
-			  "Read device characteristics failed, rc=%d for "
-			  "device: %s", rc, dev_name(&device->cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
+				"Read device characteristic failed, rc=%d", rc);
 		goto out_err3;
 	}
 	/* find the vaild cylinder size */
@@ -3290,9 +3285,8 @@
 	rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
 					 &temp_rdc_data, 64);
 	if (rc) {
-		DBF_EVENT(DBF_WARNING,
-			  "Read device characteristics failed, rc=%d for "
-			  "device: %s", rc, dev_name(&device->cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
+				"Read device characteristic failed, rc=%d", rc);
 		goto out_err;
 	}
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
Index: quilt-2.6/drivers/s390/block/dasd_fba.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_fba.c	2009-11-13 16:08:14.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_fba.c	2009-11-13 16:08:17.000000000 +0100
@@ -140,9 +140,8 @@
 	}
 	block = dasd_alloc_block();
 	if (IS_ERR(block)) {
-		DBF_EVENT(DBF_WARNING, "could not allocate dasd block "
-			  "structure for device: %s",
-			  dev_name(&device->cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s", "could not allocate "
+				"dasd block structure");
 		device->private = NULL;
 		kfree(private);
 		return PTR_ERR(block);
@@ -154,9 +153,8 @@
 	rc = dasd_generic_read_dev_chars(device, DASD_FBA_MAGIC,
 					 &private->rdc_data, 32);
 	if (rc) {
-		DBF_EVENT(DBF_WARNING, "Read device characteristics returned "
-			  "error %d for device: %s",
-			  rc, dev_name(&device->cdev->dev));
+		DBF_EVENT_DEVID(DBF_WARNING, cdev, "Read device "
+				"characteristics returned error %d", rc);
 		device->block = NULL;
 		dasd_free_block(block);
 		device->private = NULL;
Index: quilt-2.6/drivers/s390/block/dasd_int.h
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_int.h	2009-11-13 16:08:16.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_int.h	2009-11-13 16:08:17.000000000 +0100
@@ -108,6 +108,16 @@
 			    d_data); \
 } while(0)
 
+#define DBF_EVENT_DEVID(d_level, d_cdev, d_str, d_data...)	\
+do { \
+	struct ccw_dev_id __dev_id;			\
+	ccw_device_get_id(d_cdev, &__dev_id);		\
+	debug_sprintf_event(dasd_debug_area,		\
+			    d_level,					\
+			    "0.%x.%04x " d_str "\n",			\
+			    __dev_id.ssid, __dev_id.devno, d_data);	\
+} while (0)
+
 #define DBF_EXC(d_level, d_str, d_data...)\
 do { \
 	debug_sprintf_exception(dasd_debug_area, \

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 24/52] [PATCH] s390: use change recording override for kernel mapping
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (22 preceding siblings ...)
  2009-11-13 15:08 ` [patch 23/52] [PATCH] dasd: remove strings from s390dbf Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 25/52] [PATCH] sclp: improve servicability setting Martin Schwidefsky
                   ` (28 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Christian Borntraeger, Martin Schwidefsky

[-- Attachment #1: 123-dirty-override.diff --]
[-- Type: text/plain, Size: 2904 bytes --]

From: Christian Borntraeger <borntraeger@de.ibm.com>

We dont need the dirty bit if a write access is done via the kernel
mapping. In that case SetPageDirty and friends are used anyway, no
need to do that a second time. We can use the change-recording
overide function for the kernel mapping, if available.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/include/asm/pgtable.h |    4 +++-
 arch/s390/mm/vmem.c             |   11 ++++++++---
 2 files changed, 11 insertions(+), 4 deletions(-)

Index: quilt-2.6/arch/s390/include/asm/pgtable.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/pgtable.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/pgtable.h	2009-11-13 16:08:17.000000000 +0100
@@ -169,12 +169,13 @@
  * STL Segment-Table-Length:  Segment-table length (STL+1*16 entries -> up to 2048)
  *
  * A 64 bit pagetable entry of S390 has following format:
- * |                     PFRA                         |0IP0|  OS  |
+ * |			 PFRA			      |0IPC|  OS  |
  * 0000000000111111111122222222223333333333444444444455555555556666
  * 0123456789012345678901234567890123456789012345678901234567890123
  *
  * I Page-Invalid Bit:    Page is not available for address-translation
  * P Page-Protection Bit: Store access not possible for page
+ * C Change-bit override: HW is not required to set change bit
  *
  * A 64 bit segmenttable entry of S390 has following format:
  * |        P-table origin                              |      TT
@@ -218,6 +219,7 @@
  */
 
 /* Hardware bits in the page table entry */
+#define _PAGE_CO	0x100		/* HW Change-bit override */
 #define _PAGE_RO	0x200		/* HW read-only bit  */
 #define _PAGE_INVALID	0x400		/* HW invalid bit    */
 
Index: quilt-2.6/arch/s390/mm/vmem.c
===================================================================
--- quilt-2.6.orig/arch/s390/mm/vmem.c	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/mm/vmem.c	2009-11-13 16:08:17.000000000 +0100
@@ -70,8 +70,12 @@
 		pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t));
 	if (!pte)
 		return NULL;
-	clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
-		    PTRS_PER_PTE * sizeof(pte_t));
+	if (MACHINE_HAS_HPAGE)
+		clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY | _PAGE_CO,
+			    PTRS_PER_PTE * sizeof(pte_t));
+	else
+		clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
+			    PTRS_PER_PTE * sizeof(pte_t));
 	return pte;
 }
 
@@ -112,7 +116,8 @@
 		if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
 		    (address + HPAGE_SIZE <= start + size) &&
 		    (address >= HPAGE_SIZE)) {
-			pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
+			pte_val(pte) |= _SEGMENT_ENTRY_LARGE |
+					_SEGMENT_ENTRY_CO;
 			pmd_val(*pm_dir) = pte_val(pte);
 			address += HPAGE_SIZE - PAGE_SIZE;
 			continue;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 25/52] [PATCH] sclp: improve servicability setting
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (23 preceding siblings ...)
  2009-11-13 15:08 ` [patch 24/52] [PATCH] s390: use change recording override for kernel mapping Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 26/52] [PATCH] cio: fix double free in case of probe failure Martin Schwidefsky
                   ` (27 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390; +Cc: Heiko Carstens, Martin Schwidefsky

[-- Attachment #1: 124-sclp-dump-indicator.diff --]
[-- Type: text/plain, Size: 793 bytes --]

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Set dump indicator on read-scp-info command to get meaningful dumps.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/char/sclp_cmd.c |    1 +
 1 file changed, 1 insertion(+)

Index: quilt-2.6/drivers/s390/char/sclp_cmd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/char/sclp_cmd.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/char/sclp_cmd.c	2009-11-13 16:08:17.000000000 +0100
@@ -84,6 +84,7 @@
 		do {
 			memset(sccb, 0, sizeof(*sccb));
 			sccb->header.length = sizeof(*sccb);
+			sccb->header.function_code = 0x80;
 			sccb->header.control_mask[2] = 0x80;
 			rc = sclp_cmd_sync_early(commands[i], sccb);
 		} while (rc == -EBUSY);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 26/52] [PATCH] cio: fix double free in case of probe failure
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (24 preceding siblings ...)
  2009-11-13 15:08 ` [patch 25/52] [PATCH] sclp: improve servicability setting Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 27/52] [PATCH] cio: fix repeat setting of cdev parent association Martin Schwidefsky
                   ` (26 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 125-cio-probe-free.diff --]
[-- Type: text/plain, Size: 1968 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

io_subchannel_probe() frees memory for sch->private which is later
freed again when io_subchannel_remove() is called. Fix this problem
by removing the cleanup in io_subchannel_probe().

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |   11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:17.000000000 +0100
@@ -1292,7 +1292,7 @@
 	sch->private = kzalloc(sizeof(struct io_subchannel_private),
 			       GFP_KERNEL | GFP_DMA);
 	if (!sch->private)
-		goto out_err;
+		goto out_schedule;
 	/*
 	 * First check if a fitting device may be found amongst the
 	 * disconnected devices or in the orphanage.
@@ -1317,7 +1317,7 @@
 	}
 	cdev = io_subchannel_create_ccwdev(sch);
 	if (IS_ERR(cdev))
-		goto out_err;
+		goto out_schedule;
 	rc = io_subchannel_recog(cdev, sch);
 	if (rc) {
 		spin_lock_irqsave(sch->lock, flags);
@@ -1325,9 +1325,7 @@
 		spin_unlock_irqrestore(sch->lock, flags);
 	}
 	return 0;
-out_err:
-	kfree(sch->private);
-	sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
+
 out_schedule:
 	io_subchannel_schedule_removal(sch);
 	return 0;
@@ -1341,13 +1339,14 @@
 
 	cdev = sch_get_cdev(sch);
 	if (!cdev)
-		return 0;
+		goto out_free;
 	/* Set ccw device to not operational and drop reference. */
 	spin_lock_irqsave(cdev->ccwlock, flags);
 	sch_set_cdev(sch, NULL);
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	spin_unlock_irqrestore(cdev->ccwlock, flags);
 	ccw_device_unregister(cdev);
+out_free:
 	kfree(sch->private);
 	sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
 	return 0;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 27/52] [PATCH] cio: fix repeat setting of cdev parent association
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (25 preceding siblings ...)
  2009-11-13 15:08 ` [patch 26/52] [PATCH] cio: fix double free in case of probe failure Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 28/52] [PATCH] cio: introduce parent-initiated device move Martin Schwidefsky
                   ` (25 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 126-cio-parent-assoc.diff --]
[-- Type: text/plain, Size: 1417 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

sch_create_and_recog_new_device() associates a parent subchannel
with its ccw device child even though this is already done by
the subsequently called io_subchannel_recog(). Also make sure
io_subchannel_recog() sets the association under lock.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:17.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:17.000000000 +0100
@@ -888,9 +888,6 @@
 		css_sch_device_unregister(sch);
 		return;
 	}
-	spin_lock_irq(sch->lock);
-	sch_set_cdev(sch, cdev);
-	spin_unlock_irq(sch->lock);
 	/* Start recognition for the new ccw device. */
 	if (io_subchannel_recog(cdev, sch)) {
 		spin_lock_irq(sch->lock);
@@ -1107,7 +1104,6 @@
 	int rc;
 	struct ccw_device_private *priv;
 
-	sch_set_cdev(sch, cdev);
 	cdev->ccwlock = sch->lock;
 
 	/* Init private data. */
@@ -1125,6 +1121,7 @@
 
 	/* Start async. device sensing. */
 	spin_lock_irq(sch->lock);
+	sch_set_cdev(sch, cdev);
 	rc = ccw_device_recognition(cdev);
 	spin_unlock_irq(sch->lock);
 	if (rc) {

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 28/52] [PATCH] cio: introduce parent-initiated device move
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (26 preceding siblings ...)
  2009-11-13 15:08 ` [patch 27/52] [PATCH] cio: fix repeat setting of cdev parent association Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 29/52] [PATCH] cio: introduce subchannel todos Martin Schwidefsky
                   ` (24 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 127-cio-parent-move.diff --]
[-- Type: text/plain, Size: 20444 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Change the initiative to update subchannel-ccw device associations
to the subchannel: when there is an indication that the internal
association no longer reflects the current hardware state, mark
each affected subchannel as requiring attention. Once processing
reaches a subchannel, determine the correct association for that
subchannel at that time and perform the necessary device_move
operations.

This change fixes problems with the previous approach which would
leave devices in an inconsistent state when a new hardware change
occurred while a device_move was already scheduled.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/css.c        |    9 
 drivers/s390/cio/device.c     |  515 ++++++++++++++----------------------------
 drivers/s390/cio/device_fsm.c |    8 
 3 files changed, 193 insertions(+), 339 deletions(-)

Index: quilt-2.6/drivers/s390/cio/css.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/css.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/css.c	2009-11-13 16:08:18.000000000 +0100
@@ -376,8 +376,8 @@
 		/* Unusable - ignore. */
 		return 0;
 	}
-	CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, unknown, "
-			 "slow path.\n", schid.ssid, schid.sch_no, CIO_OPER);
+	CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new\n", schid.ssid,
+		      schid.sch_no);
 
 	return css_probe_device(schid);
 }
@@ -394,6 +394,10 @@
 				"Got subchannel machine check but "
 				"no sch_event handler provided.\n");
 	}
+	if (ret != 0 && ret != -EAGAIN) {
+		CIO_MSG_EVENT(2, "eval: sch 0.%x.%04x, rc=%d\n",
+			      sch->schid.ssid, sch->schid.sch_no, ret);
+	}
 	return ret;
 }
 
@@ -684,6 +688,7 @@
 	css->pseudo_subchannel->dev.parent = &css->device;
 	css->pseudo_subchannel->dev.release = css_subchannel_release;
 	dev_set_name(&css->pseudo_subchannel->dev, "defunct");
+	mutex_init(&css->pseudo_subchannel->reg_mutex);
 	ret = cio_create_sch_lock(css->pseudo_subchannel);
 	if (ret) {
 		kfree(css->pseudo_subchannel);
Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:17.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
@@ -673,57 +673,19 @@
 	return ret;
 }
 
-struct match_data {
-	struct ccw_dev_id dev_id;
-	struct ccw_device * sibling;
-};
-
-static int
-match_devno(struct device * dev, void * data)
-{
-	struct match_data * d = data;
-	struct ccw_device * cdev;
-
-	cdev = to_ccwdev(dev);
-	if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
-	    !ccw_device_is_orphan(cdev) &&
-	    ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
-	    (cdev != d->sibling))
-		return 1;
-	return 0;
-}
-
-static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
-						     struct ccw_device *sibling)
+static int match_dev_id(struct device *dev, void *data)
 {
-	struct device *dev;
-	struct match_data data;
-
-	data.dev_id = *dev_id;
-	data.sibling = sibling;
-	dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno);
-
-	return dev ? to_ccwdev(dev) : NULL;
-}
-
-static int match_orphan(struct device *dev, void *data)
-{
-	struct ccw_dev_id *dev_id;
-	struct ccw_device *cdev;
+	struct ccw_device *cdev = to_ccwdev(dev);
+	struct ccw_dev_id *dev_id = data;
 
-	dev_id = data;
-	cdev = to_ccwdev(dev);
 	return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
 }
 
-static struct ccw_device *
-get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
-			      struct ccw_dev_id *dev_id)
+static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
 {
 	struct device *dev;
 
-	dev = device_find_child(&css->pseudo_subchannel->dev, dev_id,
-				match_orphan);
+	dev = bus_find_device(&ccw_bus_type, NULL, dev_id, match_dev_id);
 
 	return dev ? to_ccwdev(dev) : NULL;
 }
@@ -808,75 +770,6 @@
 
 static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
 
-static void sch_attach_device(struct subchannel *sch,
-			      struct ccw_device *cdev)
-{
-	css_update_ssd_info(sch);
-	spin_lock_irq(sch->lock);
-	sch_set_cdev(sch, cdev);
-	cdev->private->schid = sch->schid;
-	cdev->ccwlock = sch->lock;
-	ccw_device_trigger_reprobe(cdev);
-	spin_unlock_irq(sch->lock);
-}
-
-static void sch_attach_disconnected_device(struct subchannel *sch,
-					   struct ccw_device *cdev)
-{
-	struct subchannel *other_sch;
-	int ret;
-
-	/* Get reference for new parent. */
-	if (!get_device(&sch->dev))
-		return;
-	other_sch = to_subchannel(cdev->dev.parent);
-	/* Note: device_move() changes cdev->dev.parent */
-	ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
-	if (ret) {
-		CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
-			      "(ret=%d)!\n", cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno, ret);
-		/* Put reference for new parent. */
-		put_device(&sch->dev);
-		return;
-	}
-	sch_set_cdev(other_sch, NULL);
-	/* No need to keep a subchannel without ccw device around. */
-	css_sch_device_unregister(other_sch);
-	sch_attach_device(sch, cdev);
-	/* Put reference for old parent. */
-	put_device(&other_sch->dev);
-}
-
-static void sch_attach_orphaned_device(struct subchannel *sch,
-				       struct ccw_device *cdev)
-{
-	int ret;
-	struct subchannel *pseudo_sch;
-
-	/* Get reference for new parent. */
-	if (!get_device(&sch->dev))
-		return;
-	pseudo_sch = to_subchannel(cdev->dev.parent);
-	/*
-	 * Try to move the ccw device to its new subchannel.
-	 * Note: device_move() changes cdev->dev.parent
-	 */
-	ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
-	if (ret) {
-		CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
-			      "failed (ret=%d)!\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno, ret);
-		/* Put reference for new parent. */
-		put_device(&sch->dev);
-		return;
-	}
-	sch_attach_device(sch, cdev);
-	/* Put reference on pseudo subchannel. */
-	put_device(&pseudo_sch->dev);
-}
-
 static void sch_create_and_recog_new_device(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
@@ -901,70 +794,6 @@
 	}
 }
 
-
-void ccw_device_move_to_orphanage(struct work_struct *work)
-{
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-	struct ccw_device *replacing_cdev;
-	struct subchannel *sch;
-	int ret;
-	struct channel_subsystem *css;
-	struct ccw_dev_id dev_id;
-
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
-	sch = to_subchannel(cdev->dev.parent);
-	css = to_css(sch->dev.parent);
-	dev_id.devno = sch->schib.pmcw.dev;
-	dev_id.ssid = sch->schid.ssid;
-
-	/* Increase refcount for pseudo subchannel. */
-	get_device(&css->pseudo_subchannel->dev);
-	/*
-	 * Move the orphaned ccw device to the orphanage so the replacing
-	 * ccw device can take its place on the subchannel.
-	 * Note: device_move() changes cdev->dev.parent
-	 */
-	ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev,
-		DPM_ORDER_NONE);
-	if (ret) {
-		CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
-			      "(ret=%d)!\n", cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno, ret);
-		/* Decrease refcount for pseudo subchannel again. */
-		put_device(&css->pseudo_subchannel->dev);
-		return;
-	}
-	cdev->ccwlock = css->pseudo_subchannel->lock;
-	/*
-	 * Search for the replacing ccw device
-	 * - among the disconnected devices
-	 * - in the orphanage
-	 */
-	replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
-	if (replacing_cdev) {
-		sch_attach_disconnected_device(sch, replacing_cdev);
-		/* Release reference from get_disc_ccwdev_by_dev_id() */
-		put_device(&replacing_cdev->dev);
-		/* Release reference of subchannel from old cdev. */
-		put_device(&sch->dev);
-		return;
-	}
-	replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
-	if (replacing_cdev) {
-		sch_attach_orphaned_device(sch, replacing_cdev);
-		/* Release reference from get_orphaned_ccwdev_by_dev_id() */
-		put_device(&replacing_cdev->dev);
-		/* Release reference of subchannel from old cdev. */
-		put_device(&sch->dev);
-		return;
-	}
-	sch_create_and_recog_new_device(sch);
-	/* Release reference of subchannel from old cdev. */
-	put_device(&sch->dev);
-}
-
 /*
  * Register recognized device.
  */
@@ -1131,53 +960,56 @@
 	return rc;
 }
 
-static void ccw_device_move_to_sch(struct work_struct *work)
+static int ccw_device_move_to_sch(struct ccw_device *cdev,
+				  struct subchannel *sch)
 {
-	struct ccw_device_private *priv;
+	struct subchannel *old_sch;
 	int rc;
-	struct subchannel *sch;
-	struct ccw_device *cdev;
-	struct subchannel *former_parent;
 
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	sch = priv->sch;
-	cdev = priv->cdev;
-	former_parent = to_subchannel(cdev->dev.parent);
-	/* Get reference for new parent. */
+	old_sch = to_subchannel(cdev->dev.parent);
+	/* Obtain child reference for new parent. */
 	if (!get_device(&sch->dev))
-		return;
+		return -ENODEV;
 	mutex_lock(&sch->reg_mutex);
-	/*
-	 * Try to move the ccw device to its new subchannel.
-	 * Note: device_move() changes cdev->dev.parent
-	 */
 	rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
 	mutex_unlock(&sch->reg_mutex);
 	if (rc) {
-		CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel "
-			      "0.%x.%04x failed (ret=%d)!\n",
+		CIO_MSG_EVENT(0, "device_move(0.%x.%04x,0.%x.%04x)=%d\n",
 			      cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no, rc);
-		css_sch_device_unregister(sch);
-		/* Put reference for new parent again. */
+			      sch->schib.pmcw.dev, rc);
+		/* Release child reference for new parent. */
 		put_device(&sch->dev);
-		goto out;
-	}
-	if (!sch_is_pseudo_sch(former_parent)) {
-		spin_lock_irq(former_parent->lock);
-		sch_set_cdev(former_parent, NULL);
-		spin_unlock_irq(former_parent->lock);
-		css_sch_device_unregister(former_parent);
-		/* Reset intparm to zeroes. */
-		former_parent->config.intparm = 0;
-		cio_commit_config(former_parent);
+		return rc;
 	}
-	sch_attach_device(sch, cdev);
-out:
-	/* Put reference for old parent. */
-	put_device(&former_parent->dev);
-	put_device(&cdev->dev);
+	/* Clean up old subchannel. */
+	if (!sch_is_pseudo_sch(old_sch)) {
+		spin_lock_irq(old_sch->lock);
+		sch_set_cdev(old_sch, NULL);
+		cio_disable_subchannel(old_sch);
+		spin_unlock_irq(old_sch->lock);
+		css_schedule_eval(old_sch->schid);
+	}
+	/* Release child reference for old parent. */
+	put_device(&old_sch->dev);
+	/* Initialize new subchannel. */
+	spin_lock_irq(sch->lock);
+	cdev->private->schid = sch->schid;
+	cdev->ccwlock = sch->lock;
+	if (!sch_is_pseudo_sch(sch))
+		sch_set_cdev(sch, cdev);
+	spin_unlock_irq(sch->lock);
+	if (!sch_is_pseudo_sch(sch))
+		css_update_ssd_info(sch);
+	return 0;
+}
+
+static int ccw_device_move_to_orph(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct channel_subsystem *css = to_css(sch->dev.parent);
+
+	return ccw_device_move_to_sch(cdev, css->pseudo_subchannel);
 }
 
 static void io_subchannel_irq(struct subchannel *sch)
@@ -1244,8 +1076,6 @@
 {
 	struct ccw_device *cdev;
 	int rc;
-	unsigned long flags;
-	struct ccw_dev_id dev_id;
 
 	if (cio_is_console(sch->schid)) {
 		rc = sysfs_create_group(&sch->dev.kobj,
@@ -1290,37 +1120,7 @@
 			       GFP_KERNEL | GFP_DMA);
 	if (!sch->private)
 		goto out_schedule;
-	/*
-	 * First check if a fitting device may be found amongst the
-	 * disconnected devices or in the orphanage.
-	 */
-	dev_id.devno = sch->schib.pmcw.dev;
-	dev_id.ssid = sch->schid.ssid;
-	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
-	if (!cdev)
-		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
-						     &dev_id);
-	if (cdev) {
-		/*
-		 * Schedule moving the device until when we have a registered
-		 * subchannel to move to and succeed the probe. We can
-		 * unregister later again, when the probe is through.
-		 */
-		cdev->private->sch = sch;
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_move_to_sch);
-		queue_work(slow_path_wq, &cdev->private->kick_work);
-		return 0;
-	}
-	cdev = io_subchannel_create_ccwdev(sch);
-	if (IS_ERR(cdev))
-		goto out_schedule;
-	rc = io_subchannel_recog(cdev, sch);
-	if (rc) {
-		spin_lock_irqsave(sch->lock, flags);
-		io_subchannel_recog_done(cdev);
-		spin_unlock_irqrestore(sch->lock, flags);
-	}
+	css_schedule_eval(sch->schid);
 	return 0;
 
 out_schedule:
@@ -1349,16 +1149,6 @@
 	return 0;
 }
 
-static int io_subchannel_notify(struct subchannel *sch, int event)
-{
-	struct ccw_device *cdev;
-
-	cdev = sch_get_cdev(sch);
-	if (!cdev)
-		return 0;
-	return ccw_device_notify(cdev, event);
-}
-
 static void io_subchannel_verify(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
@@ -1482,19 +1272,6 @@
 	cio_disable_subchannel(sch);
 }
 
-static int io_subchannel_get_status(struct subchannel *sch)
-{
-	struct schib schib;
-
-	if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
-		return CIO_GONE;
-	if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
-		return CIO_REVALIDATE;
-	if (!sch->lpm)
-		return CIO_NO_PATH;
-	return CIO_OPER;
-}
-
 static int device_is_disconnected(struct ccw_device *cdev)
 {
 	if (!cdev)
@@ -1626,91 +1403,165 @@
 	cdev->private->state = DEV_STATE_NOT_OPER;
 }
 
-static int io_subchannel_sch_event(struct subchannel *sch, int slow)
+enum io_sch_action {
+	IO_SCH_UNREG,
+	IO_SCH_ORPH_UNREG,
+	IO_SCH_ATTACH,
+	IO_SCH_UNREG_ATTACH,
+	IO_SCH_ORPH_ATTACH,
+	IO_SCH_REPROBE,
+	IO_SCH_VERIFY,
+	IO_SCH_DISC,
+	IO_SCH_NOP,
+};
+
+static enum io_sch_action sch_get_action(struct subchannel *sch)
+{
+	struct ccw_device *cdev;
+
+	cdev = sch_get_cdev(sch);
+	if (cio_update_schib(sch)) {
+		/* Not operational. */
+		if (!cdev)
+			return IO_SCH_UNREG;
+		if (!ccw_device_notify(cdev, CIO_GONE))
+			return IO_SCH_UNREG;
+		return IO_SCH_ORPH_UNREG;
+	}
+	/* Operational. */
+	if (!cdev)
+		return IO_SCH_ATTACH;
+	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+		if (!ccw_device_notify(cdev, CIO_GONE))
+			return IO_SCH_UNREG_ATTACH;
+		return IO_SCH_ORPH_ATTACH;
+	}
+	if ((sch->schib.pmcw.pam & sch->opm) == 0) {
+		if (!ccw_device_notify(cdev, CIO_NO_PATH))
+			return IO_SCH_UNREG;
+		return IO_SCH_DISC;
+	}
+	if (device_is_disconnected(cdev))
+		return IO_SCH_REPROBE;
+	if (cdev->online)
+		return IO_SCH_VERIFY;
+	return IO_SCH_NOP;
+}
+
+/**
+ * io_subchannel_sch_event - process subchannel event
+ * @sch: subchannel
+ * @process: non-zero if function is called in process context
+ *
+ * An unspecified event occurred for this subchannel. Adjust data according
+ * to the current operational state of the subchannel and device. Return
+ * zero when the event has been handled sufficiently or -EAGAIN when this
+ * function should be called again in process context.
+ */
+static int io_subchannel_sch_event(struct subchannel *sch, int process)
 {
-	int event, ret, disc;
 	unsigned long flags;
-	enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE, DISC } action;
 	struct ccw_device *cdev;
+	struct ccw_dev_id dev_id;
+	enum io_sch_action action;
+	int rc = -EAGAIN;
 
 	spin_lock_irqsave(sch->lock, flags);
+	if (!device_is_registered(&sch->dev))
+		goto out_unlock;
+	action = sch_get_action(sch);
+	CIO_MSG_EVENT(2, "event: sch 0.%x.%04x, process=%d, action=%d\n",
+		      sch->schid.ssid, sch->schid.sch_no, process,
+		      action);
+	/* Perform immediate actions while holding the lock. */
 	cdev = sch_get_cdev(sch);
-	disc = device_is_disconnected(cdev);
-	if (disc && slow) {
-		/* Disconnected devices are evaluated directly only.*/
-		spin_unlock_irqrestore(sch->lock, flags);
-		return 0;
-	}
-	/* No interrupt after machine check - kill pending timers. */
-	if (cdev)
-		ccw_device_set_timeout(cdev, 0);
-	if (!disc && !slow) {
-		/* Non-disconnected devices are evaluated on the slow path. */
-		spin_unlock_irqrestore(sch->lock, flags);
-		return -EAGAIN;
+	switch (action) {
+	case IO_SCH_REPROBE:
+		/* Trigger device recognition. */
+		ccw_device_trigger_reprobe(cdev);
+		rc = 0;
+		goto out_unlock;
+	case IO_SCH_VERIFY:
+		/* Trigger path verification. */
+		io_subchannel_verify(sch);
+		rc = 0;
+		goto out_unlock;
+	case IO_SCH_DISC:
+		ccw_device_set_disconnected(cdev);
+		rc = 0;
+		goto out_unlock;
+	case IO_SCH_ORPH_UNREG:
+	case IO_SCH_ORPH_ATTACH:
+		ccw_device_set_disconnected(cdev);
+		break;
+	case IO_SCH_UNREG_ATTACH:
+	case IO_SCH_UNREG:
+		if (cdev)
+			ccw_device_set_notoper(cdev);
+		break;
+	case IO_SCH_NOP:
+		rc = 0;
+		goto out_unlock;
+	default:
+		break;
 	}
-	event = io_subchannel_get_status(sch);
-	CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
-		      sch->schid.ssid, sch->schid.sch_no, event,
-		      disc ? "disconnected" : "normal",
-		      slow ? "slow" : "fast");
-	/* Analyze subchannel status. */
-	action = NONE;
-	switch (event) {
-	case CIO_NO_PATH:
-		if (disc) {
-			/* Check if paths have become available. */
-			action = REPROBE;
-			break;
-		}
-		/* fall through */
-	case CIO_GONE:
-		/* Ask driver what to do with device. */
-		if (io_subchannel_notify(sch, event))
-			action = DISC;
-		else
-			action = UNREGISTER;
+	spin_unlock_irqrestore(sch->lock, flags);
+	/* All other actions require process context. */
+	if (!process)
+		goto out;
+	/* Handle attached ccw device. */
+	switch (action) {
+	case IO_SCH_ORPH_UNREG:
+	case IO_SCH_ORPH_ATTACH:
+		/* Move ccw device to orphanage. */
+		rc = ccw_device_move_to_orph(cdev);
+		if (rc)
+			goto out;
 		break;
-	case CIO_REVALIDATE:
-		/* Device will be removed, so no notify necessary. */
-		if (disc)
-			/* Reprobe because immediate unregister might block. */
-			action = REPROBE;
-		else
-			action = UNREGISTER_PROBE;
+	case IO_SCH_UNREG_ATTACH:
+		/* Unregister ccw device. */
+		ccw_device_unregister(cdev);
 		break;
-	case CIO_OPER:
-		if (disc)
-			/* Get device operational again. */
-			action = REPROBE;
+	default:
 		break;
 	}
-	/* Perform action. */
-	ret = 0;
+	/* Handle subchannel. */
 	switch (action) {
-	case UNREGISTER:
-	case UNREGISTER_PROBE:
-		ccw_device_set_notoper(cdev);
-		/* Unregister device (will use subchannel lock). */
-		spin_unlock_irqrestore(sch->lock, flags);
+	case IO_SCH_ORPH_UNREG:
+	case IO_SCH_UNREG:
 		css_sch_device_unregister(sch);
-		spin_lock_irqsave(sch->lock, flags);
 		break;
-	case REPROBE:
+	case IO_SCH_ORPH_ATTACH:
+	case IO_SCH_UNREG_ATTACH:
+	case IO_SCH_ATTACH:
+		dev_id.ssid = sch->schid.ssid;
+		dev_id.devno = sch->schib.pmcw.dev;
+		cdev = get_ccwdev_by_dev_id(&dev_id);
+		if (!cdev) {
+			sch_create_and_recog_new_device(sch);
+			break;
+		}
+		rc = ccw_device_move_to_sch(cdev, sch);
+		if (rc) {
+			/* Release reference from get_ccwdev_by_dev_id() */
+			put_device(&cdev->dev);
+			goto out;
+		}
+		spin_lock_irqsave(sch->lock, flags);
 		ccw_device_trigger_reprobe(cdev);
-		break;
-	case DISC:
-		ccw_device_set_disconnected(cdev);
+		spin_unlock_irqrestore(sch->lock, flags);
+		/* Release reference from get_ccwdev_by_dev_id() */
+		put_device(&cdev->dev);
 		break;
 	default:
 		break;
 	}
-	spin_unlock_irqrestore(sch->lock, flags);
-	/* Probe if necessary. */
-	if (action == UNREGISTER_PROBE)
-		ret = css_probe_device(sch->schid);
+	return 0;
 
-	return ret;
+out_unlock:
+	spin_unlock_irqrestore(sch->lock, flags);
+out:
+	return rc;
 }
 
 #ifdef CONFIG_CCW_CONSOLE
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:18.000000000 +0100
@@ -1072,11 +1072,9 @@
 
 	/* We should also udate ssd info, but this has to wait. */
 	/* Check if this is another device which appeared on the same sch. */
-	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_move_to_orphanage);
-		queue_work(slow_path_wq, &cdev->private->kick_work);
-	} else
+	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno)
+		css_schedule_eval(sch->schid);
+	else
 		ccw_device_start_id(cdev, 0);
 }
 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 29/52] [PATCH] cio: introduce subchannel todos
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (27 preceding siblings ...)
  2009-11-13 15:08 ` [patch 28/52] [PATCH] cio: introduce parent-initiated device move Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 30/52] [PATCH] cio: introduce ccw device todos Martin Schwidefsky
                   ` (23 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 128-cio-subchannel-todos.diff --]
[-- Type: text/plain, Size: 5508 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Ensure that current and future users of sch->work do not overwrite
each other by introducing a single mechanism for delayed subchannel
work.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/cio.h    |    8 ++++++-
 drivers/s390/cio/css.c    |   48 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/s390/cio/css.h    |    3 ++
 drivers/s390/cio/device.c |   23 ++++------------------
 4 files changed, 63 insertions(+), 19 deletions(-)

Index: quilt-2.6/drivers/s390/cio/cio.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/cio.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/cio.h	2009-11-13 16:08:18.000000000 +0100
@@ -68,6 +68,11 @@
 	__u8 mda[4];		 /* model dependent area */
 } __attribute__ ((packed,aligned(4)));
 
+enum sch_todo {
+	SCH_TODO_NOTHING,
+	SCH_TODO_UNREG,
+};
+
 /* subchannel data structure used by I/O subroutines */
 struct subchannel {
 	struct subchannel_id schid;
@@ -95,7 +100,8 @@
 	struct device dev;	/* entry in device tree */
 	struct css_driver *driver;
 	void *private; /* private per subchannel type data */
-	struct work_struct work;
+	enum sch_todo todo;
+	struct work_struct todo_work;
 	struct schib_config config;
 } __attribute__ ((aligned(8)));
 
Index: quilt-2.6/drivers/s390/cio/css.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/css.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/css.c	2009-11-13 16:08:18.000000000 +0100
@@ -133,6 +133,8 @@
 	return rc;
 }
 
+static void css_sch_todo(struct work_struct *work);
+
 static struct subchannel *
 css_alloc_subchannel(struct subchannel_id schid)
 {
@@ -147,6 +149,7 @@
 		kfree(sch);
 		return ERR_PTR(ret);
 	}
+	INIT_WORK(&sch->todo_work, css_sch_todo);
 	return sch;
 }
 
@@ -190,6 +193,51 @@
 }
 EXPORT_SYMBOL_GPL(css_sch_device_unregister);
 
+static void css_sch_todo(struct work_struct *work)
+{
+	struct subchannel *sch;
+	enum sch_todo todo;
+
+	sch = container_of(work, struct subchannel, todo_work);
+	/* Find out todo. */
+	spin_lock_irq(sch->lock);
+	todo = sch->todo;
+	CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid,
+		      sch->schid.sch_no, todo);
+	sch->todo = SCH_TODO_NOTHING;
+	spin_unlock_irq(sch->lock);
+	/* Perform todo. */
+	if (todo == SCH_TODO_UNREG)
+		css_sch_device_unregister(sch);
+	/* Release workqueue ref. */
+	put_device(&sch->dev);
+}
+
+/**
+ * css_sched_sch_todo - schedule a subchannel operation
+ * @sch: subchannel
+ * @todo: todo
+ *
+ * Schedule the operation identified by @todo to be performed on the slow path
+ * workqueue. Do nothing if another operation with higher priority is already
+ * scheduled. Needs to be called with subchannel lock held.
+ */
+void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
+{
+	CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n",
+		      sch->schid.ssid, sch->schid.sch_no, todo);
+	if (sch->todo >= todo)
+		return;
+	/* Get workqueue ref. */
+	if (!get_device(&sch->dev))
+		return;
+	sch->todo = todo;
+	if (!queue_work(slow_path_wq, &sch->todo_work)) {
+		/* Already queued, release workqueue ref. */
+		put_device(&sch->dev);
+	}
+}
+
 static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
 {
 	int i;
Index: quilt-2.6/drivers/s390/cio/css.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/css.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/css.h	2009-11-13 16:08:18.000000000 +0100
@@ -11,6 +11,8 @@
 #include <asm/chpid.h>
 #include <asm/schid.h>
 
+#include "cio.h"
+
 /*
  * path grouping stuff
  */
@@ -151,4 +153,5 @@
 
 extern struct workqueue_struct *slow_path_wq;
 void css_wait_for_slow_path(void);
+void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo);
 #endif
Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
@@ -1051,23 +1051,6 @@
 	io_subchannel_init_config(sch);
 }
 
-static void io_subchannel_do_unreg(struct work_struct *work)
-{
-	struct subchannel *sch;
-
-	sch = container_of(work, struct subchannel, work);
-	css_sch_device_unregister(sch);
-	put_device(&sch->dev);
-}
-
-/* Schedule unregister if we have no cdev. */
-static void io_subchannel_schedule_removal(struct subchannel *sch)
-{
-	get_device(&sch->dev);
-	INIT_WORK(&sch->work, io_subchannel_do_unreg);
-	queue_work(slow_path_wq, &sch->work);
-}
-
 /*
  * Note: We always return 0 so that we bind to the device even on error.
  * This is needed so that our remove function is called on unregister.
@@ -1124,7 +1107,9 @@
 	return 0;
 
 out_schedule:
-	io_subchannel_schedule_removal(sch);
+	spin_lock_irq(sch->lock);
+	css_sched_sch_todo(sch, SCH_TODO_UNREG);
+	spin_unlock_irq(sch->lock);
 	return 0;
 }
 
@@ -1469,6 +1454,8 @@
 	spin_lock_irqsave(sch->lock, flags);
 	if (!device_is_registered(&sch->dev))
 		goto out_unlock;
+	if (work_pending(&sch->todo_work))
+		goto out_unlock;
 	action = sch_get_action(sch);
 	CIO_MSG_EVENT(2, "event: sch 0.%x.%04x, process=%d, action=%d\n",
 		      sch->schid.ssid, sch->schid.sch_no, process,

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 30/52] [PATCH] cio: introduce ccw device todos
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (28 preceding siblings ...)
  2009-11-13 15:08 ` [patch 29/52] [PATCH] cio: introduce subchannel todos Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 31/52] [PATCH] cio: inform user when online/offline processing fails Martin Schwidefsky
                   ` (22 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 129-cio-ccwdev-todos.diff --]
[-- Type: text/plain, Size: 16256 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Introduce a central mechanism for performing delayed ccw device work
to ensure that different types of work do not overwrite each other.
Prioritization ensures that the most important work is always
performed while less important tasks are either obsoleted or repeated
later.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c     |  203 ++++++++++++++++++++----------------------
 drivers/s390/cio/device.h     |    3 
 drivers/s390/cio/device_fsm.c |   28 +----
 drivers/s390/cio/io_sch.h     |   12 ++
 4 files changed, 119 insertions(+), 127 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
@@ -306,47 +306,6 @@
 	}
 }
 
-static void ccw_device_remove_orphan_cb(struct work_struct *work)
-{
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
-	ccw_device_unregister(cdev);
-	/* Release cdev reference for workqueue processing. */
-	put_device(&cdev->dev);
-}
-
-static void
-ccw_device_remove_disconnected(struct ccw_device *cdev)
-{
-	unsigned long flags;
-
-	/*
-	 * Forced offline in disconnected state means
-	 * 'throw away device'.
-	 */
-	if (ccw_device_is_orphan(cdev)) {
-		/*
-		 * Deregister ccw device.
-		 * Unfortunately, we cannot do this directly from the
-		 * attribute method.
-		 */
-		/* Get cdev reference for workqueue processing. */
-		if (!get_device(&cdev->dev))
-			return;
-		spin_lock_irqsave(cdev->ccwlock, flags);
-		cdev->private->state = DEV_STATE_NOT_OPER;
-		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		PREPARE_WORK(&cdev->private->kick_work,
-				ccw_device_remove_orphan_cb);
-		queue_work(slow_path_wq, &cdev->private->kick_work);
-	} else
-		/* Deregister subchannel, which will kill the ccw device. */
-		ccw_device_schedule_sch_unregister(cdev);
-}
-
 /**
  * ccw_device_set_offline() - disable a ccw device for I/O
  * @cdev: target ccw device
@@ -494,9 +453,11 @@
 
 static int online_store_handle_offline(struct ccw_device *cdev)
 {
-	if (cdev->private->state == DEV_STATE_DISCONNECTED)
-		ccw_device_remove_disconnected(cdev);
-	else if (cdev->online && cdev->drv && cdev->drv->set_offline)
+	if (cdev->private->state == DEV_STATE_DISCONNECTED) {
+		spin_lock_irq(cdev->ccwlock);
+		ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
+		spin_unlock_irq(cdev->ccwlock);
+	} else if (cdev->online && cdev->drv && cdev->drv->set_offline)
 		return ccw_device_set_offline(cdev);
 	return 0;
 }
@@ -690,17 +651,10 @@
 	return dev ? to_ccwdev(dev) : NULL;
 }
 
-void ccw_device_do_unbind_bind(struct work_struct *work)
+static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
 {
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-	struct subchannel *sch;
 	int ret;
 
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
-	sch = to_subchannel(cdev->dev.parent);
-
 	if (test_bit(1, &cdev->private->registered)) {
 		device_release_driver(&cdev->dev);
 		ret = device_attach(&cdev->dev);
@@ -735,6 +689,8 @@
 	return ERR_PTR(-ENOMEM);
 }
 
+static void ccw_device_todo(struct work_struct *work);
+
 static int io_subchannel_initialize_dev(struct subchannel *sch,
 					struct ccw_device *cdev)
 {
@@ -742,7 +698,7 @@
 	atomic_set(&cdev->private->onoff, 0);
 	cdev->dev.parent = &sch->dev;
 	cdev->dev.release = ccw_device_release;
-	INIT_WORK(&cdev->private->kick_work, NULL);
+	INIT_WORK(&cdev->private->todo_work, ccw_device_todo);
 	cdev->dev.groups = ccwdev_attr_groups;
 	/* Do first half of device_register. */
 	device_initialize(&cdev->dev);
@@ -797,17 +753,12 @@
 /*
  * Register recognized device.
  */
-static void
-io_subchannel_register(struct work_struct *work)
+static void io_subchannel_register(struct ccw_device *cdev)
 {
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
 	struct subchannel *sch;
 	int ret;
 	unsigned long flags;
 
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
 	sch = to_subchannel(cdev->dev.parent);
 	/*
 	 * Check if subchannel is still registered. It may have become
@@ -859,41 +810,23 @@
 	cdev->private->flags.recog_done = 1;
 	wake_up(&cdev->private->wait_q);
 out_err:
-	/* Release reference for workqueue processing. */
-	put_device(&cdev->dev);
 	if (atomic_dec_and_test(&ccw_device_init_count))
 		wake_up(&ccw_device_init_wq);
 }
 
-static void ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct ccw_device *cdev)
 {
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
 	struct subchannel *sch;
 
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
 	/* Get subchannel reference for local processing. */
 	if (!get_device(cdev->dev.parent))
 		return;
 	sch = to_subchannel(cdev->dev.parent);
 	css_sch_device_unregister(sch);
-	/* Release cdev reference for workqueue processing.*/
-	put_device(&cdev->dev);
 	/* Release subchannel reference for local processing. */
 	put_device(&sch->dev);
 }
 
-void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
-{
-	/* Get cdev reference for workqueue processing. */
-	if (!get_device(&cdev->dev))
-		return;
-	PREPARE_WORK(&cdev->private->kick_work,
-		     ccw_device_call_sch_unregister);
-	queue_work(slow_path_wq, &cdev->private->kick_work);
-}
-
 /*
  * subchannel recognition done. Called from the state machine.
  */
@@ -909,7 +842,8 @@
 		/* Device did not respond in time. */
 	case DEV_STATE_NOT_OPER:
 		cdev->private->flags.recog_done = 1;
-		ccw_device_schedule_sch_unregister(cdev);
+		/* Remove device found not operational. */
+		ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 		if (atomic_dec_and_test(&ccw_device_init_count))
 			wake_up(&ccw_device_init_wq);
 		break;
@@ -918,11 +852,7 @@
 		 * We can't register the device in interrupt context so
 		 * we schedule a work item.
 		 */
-		if (!get_device(&cdev->dev))
-			break;
-		PREPARE_WORK(&cdev->private->kick_work,
-			     io_subchannel_register);
-		queue_work(slow_path_wq, &cdev->private->kick_work);
+		ccw_device_sched_todo(cdev, CDEV_TODO_REGISTER);
 		break;
 	}
 }
@@ -1333,20 +1263,16 @@
 static int purge_fn(struct device *dev, void *data)
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
-	struct ccw_device_private *priv = cdev->private;
-	int unreg;
+	struct ccw_dev_id *id = &cdev->private->dev_id;
 
 	spin_lock_irq(cdev->ccwlock);
-	unreg = is_blacklisted(priv->dev_id.ssid, priv->dev_id.devno) &&
-		(priv->state == DEV_STATE_OFFLINE);
+	if (is_blacklisted(id->ssid, id->devno) &&
+	    (cdev->private->state == DEV_STATE_OFFLINE)) {
+		CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid,
+			      id->devno);
+		ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
+	}
 	spin_unlock_irq(cdev->ccwlock);
-	if (!unreg)
-		goto out;
-	CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
-		      priv->dev_id.devno);
-	ccw_device_schedule_sch_unregister(cdev);
-
-out:
 	/* Abort loop in case of pending signal. */
 	if (signal_pending(current))
 		return -EINTR;
@@ -1456,12 +1382,14 @@
 		goto out_unlock;
 	if (work_pending(&sch->todo_work))
 		goto out_unlock;
+	cdev = sch_get_cdev(sch);
+	if (cdev && work_pending(&cdev->private->todo_work))
+		goto out_unlock;
 	action = sch_get_action(sch);
 	CIO_MSG_EVENT(2, "event: sch 0.%x.%04x, process=%d, action=%d\n",
 		      sch->schid.ssid, sch->schid.sch_no, process,
 		      action);
 	/* Perform immediate actions while holding the lock. */
-	cdev = sch_get_cdev(sch);
 	switch (action) {
 	case IO_SCH_REPROBE:
 		/* Trigger device recognition. */
@@ -1753,7 +1681,7 @@
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
 
-	if (work_pending(&cdev->private->kick_work))
+	if (work_pending(&cdev->private->todo_work))
 		return -EAGAIN;
 	/* Fail while device is being set online/offline. */
 	if (atomic_read(&cdev->private->onoff))
@@ -1874,7 +1802,7 @@
 	cdev->private->state = DEV_STATE_BOXED;
 	if (ccw_device_notify(cdev, CIO_BOXED))
 		return 0;
-	ccw_device_schedule_sch_unregister(cdev);
+	ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 	return -ENODEV;
 }
 
@@ -1883,7 +1811,7 @@
 	cdev->private->state = DEV_STATE_DISCONNECTED;
 	if (ccw_device_notify(cdev, CIO_GONE))
 		return 0;
-	ccw_device_schedule_sch_unregister(cdev);
+	ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 	return -ENODEV;
 }
 
@@ -1928,9 +1856,7 @@
 	/* check if the device type has changed */
 	if (!ccw_device_test_sense_data(cdev)) {
 		ccw_device_update_sense_data(cdev);
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_do_unbind_bind);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
+		ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
 		ret = -ENODEV;
 		goto out_unlock;
 	}
@@ -1974,7 +1900,7 @@
 	goto out_restore;
 
 out_unreg_unlock:
-	ccw_device_schedule_sch_unregister(cdev);
+	ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
 	ret = -ENODEV;
 out_unlock:
 	spin_unlock_irq(sch->lock);
@@ -2039,6 +1965,77 @@
 	return sch->schid;
 }
 
+static void ccw_device_todo(struct work_struct *work)
+{
+	struct ccw_device_private *priv;
+	struct ccw_device *cdev;
+	struct subchannel *sch;
+	enum cdev_todo todo;
+
+	priv = container_of(work, struct ccw_device_private, todo_work);
+	cdev = priv->cdev;
+	sch = to_subchannel(cdev->dev.parent);
+	/* Find out todo. */
+	spin_lock_irq(cdev->ccwlock);
+	todo = priv->todo;
+	priv->todo = CDEV_TODO_NOTHING;
+	CIO_MSG_EVENT(4, "cdev_todo: cdev=0.%x.%04x todo=%d\n",
+		      priv->dev_id.ssid, priv->dev_id.devno, todo);
+	spin_unlock_irq(cdev->ccwlock);
+	/* Perform todo. */
+	switch (todo) {
+	case CDEV_TODO_ENABLE_CMF:
+		cmf_reenable(cdev);
+		break;
+	case CDEV_TODO_REBIND:
+		ccw_device_do_unbind_bind(cdev);
+		break;
+	case CDEV_TODO_REGISTER:
+		io_subchannel_register(cdev);
+		break;
+	case CDEV_TODO_UNREG_EVAL:
+		if (!sch_is_pseudo_sch(sch))
+			css_schedule_eval(sch->schid);
+		/* fall-through */
+	case CDEV_TODO_UNREG:
+		if (sch_is_pseudo_sch(sch))
+			ccw_device_unregister(cdev);
+		else
+			ccw_device_call_sch_unregister(cdev);
+		break;
+	default:
+		break;
+	}
+	/* Release workqueue ref. */
+	put_device(&cdev->dev);
+}
+
+/**
+ * ccw_device_sched_todo - schedule ccw device operation
+ * @cdev: ccw device
+ * @todo: todo
+ *
+ * Schedule the operation identified by @todo to be performed on the slow path
+ * workqueue. Do nothing if another operation with higher priority is already
+ * scheduled. Needs to be called with ccwdev lock held.
+ */
+void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo)
+{
+	CIO_MSG_EVENT(4, "cdev_todo: sched cdev=0.%x.%04x todo=%d\n",
+		      cdev->private->dev_id.ssid, cdev->private->dev_id.devno,
+		      todo);
+	if (cdev->private->todo >= todo)
+		return;
+	cdev->private->todo = todo;
+	/* Get workqueue ref. */
+	if (!get_device(&cdev->dev))
+		return;
+	if (!queue_work(slow_path_wq, &cdev->private->todo_work)) {
+		/* Already queued, release workqueue ref. */
+		put_device(&cdev->dev);
+	}
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:18.000000000 +0100
@@ -289,9 +289,7 @@
 			wake_up(&cdev->private->wait_q);
 		} else {
 			ccw_device_update_sense_data(cdev);
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_do_unbind_bind);
-			queue_work(ccw_device_work, &cdev->private->kick_work);
+			ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
 		}
 		return;
 	case DEV_STATE_BOXED:
@@ -343,28 +341,16 @@
 	return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
 }
 
-static void cmf_reenable_delayed(struct work_struct *work)
-{
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
-	cmf_reenable(cdev);
-}
-
 static void ccw_device_oper_notify(struct ccw_device *cdev)
 {
 	if (ccw_device_notify(cdev, CIO_OPER)) {
 		/* Reenable channel measurements, if needed. */
-		PREPARE_WORK(&cdev->private->kick_work, cmf_reenable_delayed);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
+		ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
 		return;
 	}
 	/* Driver doesn't want device back. */
 	ccw_device_set_notoper(cdev);
-	PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind);
-	queue_work(ccw_device_work, &cdev->private->kick_work);
+	ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
 }
 
 /*
@@ -392,14 +378,14 @@
 		CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
 			      cdev->private->dev_id.devno, sch->schid.sch_no);
 		if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
-			ccw_device_schedule_sch_unregister(cdev);
+			ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 		cdev->private->flags.donotify = 0;
 		break;
 	case DEV_STATE_NOT_OPER:
 		CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
 			      cdev->private->dev_id.devno, sch->schid.sch_no);
 		if (!ccw_device_notify(cdev, CIO_GONE))
-			ccw_device_schedule_sch_unregister(cdev);
+			ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 		else
 			ccw_device_set_disconnected(cdev);
 		cdev->private->flags.donotify = 0;
@@ -409,7 +395,7 @@
 			      "%04x\n", cdev->private->dev_id.devno,
 			      sch->schid.sch_no);
 		if (!ccw_device_notify(cdev, CIO_NO_PATH))
-			ccw_device_schedule_sch_unregister(cdev);
+			ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 		else
 			ccw_device_set_disconnected(cdev);
 		cdev->private->flags.donotify = 0;
@@ -751,7 +737,7 @@
 				       enum dev_event dev_event)
 {
 	if (!ccw_device_notify(cdev, CIO_GONE))
-		ccw_device_schedule_sch_unregister(cdev);
+		ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
 	else
 		ccw_device_set_disconnected(cdev);
 }
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:18.000000000 +0100
@@ -81,8 +81,6 @@
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
 
-void ccw_device_do_unbind_bind(struct work_struct *);
-void ccw_device_move_to_orphanage(struct work_struct *);
 int ccw_device_is_orphan(struct ccw_device *);
 
 int ccw_device_recognition(struct ccw_device *);
@@ -92,6 +90,7 @@
 int ccw_device_test_sense_data(struct ccw_device *);
 void ccw_device_schedule_sch_unregister(struct ccw_device *);
 int ccw_purge_blacklisted(void);
+void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo);
 
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:18.000000000 +0100
@@ -82,6 +82,15 @@
 	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
 }  __attribute__ ((packed, aligned(4)));
 
+enum cdev_todo {
+	CDEV_TODO_NOTHING,
+	CDEV_TODO_ENABLE_CMF,
+	CDEV_TODO_REBIND,
+	CDEV_TODO_REGISTER,
+	CDEV_TODO_UNREG,
+	CDEV_TODO_UNREG_EVAL,
+};
+
 struct ccw_device_private {
 	struct ccw_device *cdev;
 	struct subchannel *sch;
@@ -115,7 +124,8 @@
 	struct senseid senseid;	/* SenseID info */
 	struct pgid pgid[8];	/* path group IDs per chpid*/
 	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
-	struct work_struct kick_work;
+	struct work_struct todo_work;
+	enum cdev_todo todo;
 	wait_queue_head_t wait_q;
 	struct timer_list timer;
 	void *cmb;			/* measurement information */

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 31/52] [PATCH] cio: inform user when online/offline processing fails
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (29 preceding siblings ...)
  2009-11-13 15:08 ` [patch 30/52] [PATCH] cio: introduce ccw device todos Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 32/52] [PATCH] cio: handle error during device recognition consistently Martin Schwidefsky
                   ` (21 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 130-cio-warn-onoff-fail.diff --]
[-- Type: text/plain, Size: 2275 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Print a warning message in case a ccw device enters boxed or
not operational state during online/offline processing.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |   22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
@@ -7,6 +7,10 @@
  *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
+
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
@@ -347,6 +351,14 @@
 	spin_unlock_irq(cdev->ccwlock);
 	wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
 		   cdev->private->state == DEV_STATE_DISCONNECTED));
+	/* Inform the user if set offline failed. */
+	if (cdev->private->state == DEV_STATE_BOXED) {
+		pr_warning("%s: The device entered boxed state while "
+			   "being set offline\n", dev_name(&cdev->dev));
+	} else if (cdev->private->state == DEV_STATE_NOT_OPER) {
+		pr_warning("%s: The device stopped operating while "
+			   "being set offline\n", dev_name(&cdev->dev));
+	}
 	/* Give up reference from ccw_device_set_online(). */
 	put_device(&cdev->dev);
 	return 0;
@@ -407,6 +419,16 @@
 	if ((cdev->private->state != DEV_STATE_ONLINE) &&
 	    (cdev->private->state != DEV_STATE_W4SENSE)) {
 		spin_unlock_irq(cdev->ccwlock);
+		/* Inform the user that set online failed. */
+		if (cdev->private->state == DEV_STATE_BOXED) {
+			pr_warning("%s: Setting the device online failed "
+				   "because it is boxed\n",
+				   dev_name(&cdev->dev));
+		} else if (cdev->private->state == DEV_STATE_NOT_OPER) {
+			pr_warning("%s: Setting the device online failed "
+				   "because it is not operational\n",
+				   dev_name(&cdev->dev));
+		}
 		/* Give up online reference since onlining failed. */
 		put_device(&cdev->dev);
 		return -ENODEV;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 32/52] [PATCH] cio: handle error during device recognition consistently
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (30 preceding siblings ...)
  2009-11-13 15:08 ` [patch 31/52] [PATCH] cio: inform user when online/offline processing fails Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 33/52] [PATCH] cio: handle error during path verification consistently Martin Schwidefsky
                   ` (20 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 131-cio-error-reporting.diff --]
[-- Type: text/plain, Size: 6083 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Remove the return code from ccw_device_recognition and handle
recognition errors through the existing callback
ccw_device_recog_done to reduce cleanup code duplication.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c     |   57 +++++-------------------------------------
 drivers/s390/cio/device.h     |    2 -
 drivers/s390/cio/device_fsm.c |   20 ++++----------
 3 files changed, 15 insertions(+), 64 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
@@ -486,18 +486,9 @@
 
 static int online_store_recog_and_online(struct ccw_device *cdev)
 {
-	int ret;
-
 	/* Do device recognition, if needed. */
 	if (cdev->private->state == DEV_STATE_BOXED) {
-		ret = ccw_device_recognition(cdev);
-		if (ret) {
-			CIO_MSG_EVENT(0, "Couldn't start recognition "
-				      "for device 0.%x.%04x (ret=%d)\n",
-				      cdev->private->dev_id.ssid,
-				      cdev->private->dev_id.devno, ret);
-			return ret;
-		}
+		ccw_device_recognition(cdev);
 		wait_event(cdev->private->wait_q,
 			   cdev->private->flags.recog_done);
 		if (cdev->private->state != DEV_STATE_OFFLINE)
@@ -746,7 +737,7 @@
 	return cdev;
 }
 
-static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
+static void io_subchannel_recog(struct ccw_device *, struct subchannel *);
 
 static void sch_create_and_recog_new_device(struct subchannel *sch)
 {
@@ -760,16 +751,7 @@
 		return;
 	}
 	/* Start recognition for the new ccw device. */
-	if (io_subchannel_recog(cdev, sch)) {
-		spin_lock_irq(sch->lock);
-		sch_set_cdev(sch, NULL);
-		spin_unlock_irq(sch->lock);
-		css_sch_device_unregister(sch);
-		/* Put reference from io_subchannel_create_ccwdev(). */
-		put_device(&sch->dev);
-		/* Give up initial reference. */
-		put_device(&cdev->dev);
-	}
+	io_subchannel_recog(cdev, sch);
 }
 
 /*
@@ -879,10 +861,8 @@
 	}
 }
 
-static int
-io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
+static void io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
 {
-	int rc;
 	struct ccw_device_private *priv;
 
 	cdev->ccwlock = sch->lock;
@@ -903,13 +883,8 @@
 	/* Start async. device sensing. */
 	spin_lock_irq(sch->lock);
 	sch_set_cdev(sch, cdev);
-	rc = ccw_device_recognition(cdev);
+	ccw_device_recognition(cdev);
 	spin_unlock_irq(sch->lock);
-	if (rc) {
-		if (atomic_dec_and_test(&ccw_device_init_count))
-			wake_up(&ccw_device_init_wq);
-	}
-	return rc;
 }
 
 static int ccw_device_move_to_sch(struct ccw_device *cdev,
@@ -1528,10 +1503,7 @@
 	sch->driver = &io_subchannel_driver;
 	/* Initialize the ccw_device structure. */
 	cdev->dev.parent= &sch->dev;
-	rc = io_subchannel_recog(cdev, sch);
-	if (rc)
-		return rc;
-
+	io_subchannel_recog(cdev, sch);
 	/* Now wait for the async. recognition to come to an end. */
 	spin_lock_irq(cdev->ccwlock);
 	while (!dev_fsm_final_state(cdev))
@@ -1547,7 +1519,7 @@
 	rc = 0;
 out_unlock:
 	spin_unlock_irq(cdev->ccwlock);
-	return 0;
+	return rc;
 }
 
 struct ccw_device *
@@ -1789,7 +1761,6 @@
 static void __ccw_device_pm_restore(struct ccw_device *cdev)
 {
 	struct subchannel *sch = to_subchannel(cdev->dev.parent);
-	int ret;
 
 	if (cio_is_console(sch->schid))
 		goto out;
@@ -1799,22 +1770,10 @@
 	 */
 	spin_lock_irq(sch->lock);
 	cdev->private->flags.resuming = 1;
-	ret = ccw_device_recognition(cdev);
+	ccw_device_recognition(cdev);
 	spin_unlock_irq(sch->lock);
-	if (ret) {
-		CIO_MSG_EVENT(0, "Couldn't start recognition for device "
-			      "0.%x.%04x (ret=%d)\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno, ret);
-		spin_lock_irq(sch->lock);
-		cdev->private->state = DEV_STATE_DISCONNECTED;
-		spin_unlock_irq(sch->lock);
-		/* notify driver after the resume cb */
-		goto out;
-	}
 	wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
 		   cdev->private->state == DEV_STATE_DISCONNECTED);
-
 out:
 	cdev->private->flags.resuming = 0;
 }
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:18.000000000 +0100
@@ -498,20 +498,9 @@
 /*
  * Start device recognition.
  */
-int
-ccw_device_recognition(struct ccw_device *cdev)
+void ccw_device_recognition(struct ccw_device *cdev)
 {
-	struct subchannel *sch;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
-	if (ret != 0)
-		/* Couldn't enable the subchannel for i/o. Sick device. */
-		return ret;
-
-	/* After 60s the device recognition is considered to have failed. */
-	ccw_device_set_timeout(cdev, 60*HZ);
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
 
 	/*
 	 * We used to start here with a sense pgid to find out whether a device
@@ -523,8 +512,11 @@
 	 */
 	cdev->private->flags.recog_done = 0;
 	cdev->private->state = DEV_STATE_SENSE_ID;
+	if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) {
+		ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
+		return;
+	}
 	ccw_device_sense_id_start(cdev);
-	return 0;
 }
 
 /*
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:18.000000000 +0100
@@ -83,7 +83,7 @@
 
 int ccw_device_is_orphan(struct ccw_device *);
 
-int ccw_device_recognition(struct ccw_device *);
+void ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
 void ccw_device_update_sense_data(struct ccw_device *);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 33/52] [PATCH] cio: handle error during path verification consistently
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (31 preceding siblings ...)
  2009-11-13 15:08 ` [patch 32/52] [PATCH] cio: handle error during device recognition consistently Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 34/52] [PATCH] cio: ensure proper locking during device recognition Martin Schwidefsky
                   ` (19 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 132-cio-verification-errors.diff --]
[-- Type: text/plain, Size: 2536 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Handle verification errors consistently through the existing
callback ccw_device_done to reduce cleanup code duplication.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device_fsm.c  |   19 +++++++++----------
 drivers/s390/cio/device_pgid.c |    2 +-
 2 files changed, 10 insertions(+), 11 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:19.000000000 +0100
@@ -549,9 +549,8 @@
 	sch = to_subchannel(cdev->dev.parent);
 	/* Update schib - pom may have changed. */
 	if (cio_update_schib(sch)) {
-		cdev->private->flags.donotify = 0;
-		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
-		return;
+		err = -ENODEV;
+		goto callback;
 	}
 	/* Update lpm with verified path mask. */
 	sch->lpm = sch->vpm;
@@ -561,9 +560,8 @@
 		ccw_device_verify_start(cdev);
 		return;
 	}
+callback:
 	switch (err) {
-	case -EOPNOTSUPP: /* path grouping not supported, just set online. */
-		cdev->private->options.pgroup = 0;
 	case 0:
 		ccw_device_done(cdev, DEV_STATE_ONLINE);
 		/* Deliver fake irb to device driver, if needed. */
@@ -586,14 +584,15 @@
 		cdev->private->flags.donotify = 0;
 		ccw_device_done(cdev, DEV_STATE_BOXED);
 		break;
+	case -EACCES:
+		/* Reset oper notify indication after verify error. */
+		cdev->private->flags.donotify = 0;
+		ccw_device_done(cdev, DEV_STATE_DISCONNECTED);
+		break;
 	default:
 		/* Reset oper notify indication after verify error. */
 		cdev->private->flags.donotify = 0;
-		if (cdev->online) {
-			ccw_device_set_timeout(cdev, 0);
-			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-		} else
-			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
 }
Index: quilt-2.6/drivers/s390/cio/device_pgid.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_pgid.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:19.000000000 +0100
@@ -423,7 +423,7 @@
 		/* Permanent path failure, try next. */
 	}
 	/* Done with all paths. */
-	ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
+	ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -EACCES);
 }
 		
 /*

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 34/52] [PATCH] cio: ensure proper locking during device recognition
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (32 preceding siblings ...)
  2009-11-13 15:08 ` [patch 33/52] [PATCH] cio: handle error during path verification consistently Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:08 ` [patch 35/52] [PATCH] cio: dont panic in non-fatal conditions Martin Schwidefsky
                   ` (18 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 133-cio-recognition-locking.diff --]
[-- Type: text/plain, Size: 1017 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Device recognition needs to be started with the ccw device lock
held to prevent race conditions between I/O starting and interrupt
reception.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |    2 ++
 1 file changed, 2 insertions(+)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:19.000000000 +0100
@@ -488,7 +488,9 @@
 {
 	/* Do device recognition, if needed. */
 	if (cdev->private->state == DEV_STATE_BOXED) {
+		spin_lock_irq(cdev->ccwlock);
 		ccw_device_recognition(cdev);
+		spin_unlock_irq(cdev->ccwlock);
 		wait_event(cdev->private->wait_q,
 			   cdev->private->flags.recog_done);
 		if (cdev->private->state != DEV_STATE_OFFLINE)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 35/52] [PATCH] cio: dont panic in non-fatal conditions
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (33 preceding siblings ...)
  2009-11-13 15:08 ` [patch 34/52] [PATCH] cio: ensure proper locking during device recognition Martin Schwidefsky
@ 2009-11-13 15:08 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 36/52] [PATCH] cio: consistent infrastructure for internal I/O requests Martin Schwidefsky
                   ` (17 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:08 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 134-cio-avoid-panic.diff --]
[-- Type: text/plain, Size: 2576 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Remove the call to BUG() for situations which are unexpected
but do not cause actual problems.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device_fsm.c |   25 ++++++-------------------
 1 file changed, 6 insertions(+), 19 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:19.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:19.000000000 +0100
@@ -1055,14 +1055,14 @@
 		ccw_device_start_id(cdev, 0);
 }
 
-static void
-ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_disabled_irq(struct ccw_device *cdev,
+				    enum dev_event dev_event)
 {
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
 	/*
-	 * An interrupt in state offline means a previous disable was not
+	 * An interrupt in a disabled state means a previous disable was not
 	 * successful - should not happen, but we try to disable again.
 	 */
 	cio_disable_subchannel(sch);
@@ -1125,25 +1125,12 @@
 }
 
 /*
- * Bug operation action. 
- */
-static void
-ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	CIO_MSG_EVENT(0, "Internal state [%i][%i] not handled for device "
-		      "0.%x.%04x\n", cdev->private->state, dev_event,
-		      cdev->private->dev_id.ssid,
-		      cdev->private->dev_id.devno);
-	BUG();
-}
-
-/*
  * device statemachine
  */
 fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
 	[DEV_STATE_NOT_OPER] = {
 		[DEV_EVENT_NOTOPER]	= ccw_device_nop,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_bug,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_disabled_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
@@ -1161,7 +1148,7 @@
 	},
 	[DEV_STATE_OFFLINE] = {
 		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_offline_irq,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_disabled_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_offline_verify,
 	},
@@ -1218,7 +1205,7 @@
 	[DEV_STATE_DISCONNECTED] = {
 		[DEV_EVENT_NOTOPER]	= ccw_device_nop,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_start_id,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_bug,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_start_id,
 	},
 	[DEV_STATE_DISCONNECTED_SENSE_ID] = {

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 36/52] [PATCH] cio: consistent infrastructure for internal I/O requests
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (34 preceding siblings ...)
  2009-11-13 15:08 ` [patch 35/52] [PATCH] cio: dont panic in non-fatal conditions Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 37/52] [PATCH] cio: use ccw request infrastructure for sense id Martin Schwidefsky
                   ` (16 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 135-cio-internal-io.diff --]
[-- Type: text/plain, Size: 12285 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Reduce code duplication by introducing a central infrastructure to
perform an internal I/O operation on a CCW device.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/Makefile |    2 
 drivers/s390/cio/ccwreq.c |  327 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/s390/cio/device.h |    8 +
 drivers/s390/cio/io_sch.h |   50 +++++++
 4 files changed, 386 insertions(+), 1 deletion(-)

Index: quilt-2.6/drivers/s390/cio/ccwreq.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ quilt-2.6/drivers/s390/cio/ccwreq.c	2009-11-13 16:08:19.000000000 +0100
@@ -0,0 +1,327 @@
+/*
+ *  Handling of internal CCW device requests.
+ *
+ *    Copyright IBM Corp. 2009
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/err.h>
+#include <asm/ccwdev.h>
+#include <asm/cio.h>
+
+#include "io_sch.h"
+#include "cio.h"
+#include "device.h"
+#include "cio_debug.h"
+
+/**
+ * lpm_adjust - adjust path mask
+ * @lpm: path mask to adjust
+ * @mask: mask of available paths
+ *
+ * Shift @lpm right until @lpm and @mask have at least one bit in common or
+ * until @lpm is zero. Return the resulting lpm.
+ */
+int lpm_adjust(int lpm, int mask)
+{
+	while (lpm && ((lpm & mask) == 0))
+		lpm >>= 1;
+	return lpm;
+}
+
+/*
+ * Adjust path mask to use next path and reset retry count. Return resulting
+ * path mask.
+ */
+static u16 ccwreq_next_path(struct ccw_device *cdev)
+{
+	struct ccw_request *req = &cdev->private->req;
+
+	req->retries	= req->maxretries;
+	req->mask	= lpm_adjust(req->mask >>= 1, req->lpm);
+
+	return req->mask;
+}
+
+/*
+ * Clean up device state and report to callback.
+ */
+static void ccwreq_stop(struct ccw_device *cdev, int rc)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+
+	if (req->done)
+		return;
+	req->done = 1;
+	ccw_device_set_timeout(cdev, 0);
+	memset(&cdev->private->irb, 0, sizeof(struct irb));
+	sch->lpm = sch->schib.pmcw.pam;
+	if (rc && rc != -ENODEV && req->drc)
+		rc = req->drc;
+	req->callback(cdev, req->data, rc);
+}
+
+/*
+ * (Re-)Start the operation until retries and paths are exhausted.
+ */
+static void ccwreq_do(struct ccw_device *cdev)
+{
+	struct ccw_request *req = &cdev->private->req;
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw1 *cp = req->cp;
+	int rc = -EACCES;
+
+	while (req->mask) {
+		if (req->retries-- == 0) {
+			/* Retries exhausted, try next path. */
+			ccwreq_next_path(cdev);
+			continue;
+		}
+		/* Perform start function. */
+		sch->lpm = 0xff;
+		memset(&cdev->private->irb, 0, sizeof(struct irb));
+		rc = cio_start(sch, cp, req->mask);
+		if (rc == 0) {
+			/* I/O started successfully. */
+			ccw_device_set_timeout(cdev, req->timeout);
+			return;
+		}
+		if (rc == -ENODEV) {
+			/* Permanent device error. */
+			break;
+		}
+		if (rc == -EACCES) {
+			/* Permant path error. */
+			ccwreq_next_path(cdev);
+			continue;
+		}
+		/* Temporary improper status. */
+		rc = cio_clear(sch);
+		if (rc)
+			break;
+		return;
+	}
+	ccwreq_stop(cdev, rc);
+}
+
+/**
+ * ccw_request_start - perform I/O request
+ * @cdev: ccw device
+ *
+ * Perform the I/O request specified by cdev->req.
+ */
+void ccw_request_start(struct ccw_device *cdev)
+{
+	struct ccw_request *req = &cdev->private->req;
+
+	req->mask	= 0x80;
+	req->retries	= req->maxretries;
+	req->mask	= lpm_adjust(req->mask, req->lpm);
+	req->drc	= 0;
+	req->done	= 0;
+	req->cancel	= 0;
+	if (!req->mask)
+		goto out_nopath;
+	ccwreq_do(cdev);
+	return;
+
+out_nopath:
+	ccwreq_stop(cdev, -EACCES);
+}
+
+/**
+ * ccw_request_cancel - cancel running I/O request
+ * @cdev: ccw device
+ *
+ * Cancel the I/O request specified by cdev->req. Return non-zero if request
+ * has already finished, zero otherwise.
+ */
+int ccw_request_cancel(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+	int rc;
+
+	if (req->done)
+		return 1;
+	req->cancel = 1;
+	rc = cio_clear(sch);
+	if (rc)
+		ccwreq_stop(cdev, rc);
+	return 0;
+}
+
+/*
+ * Return the status of the internal I/O started on the specified ccw device.
+ * Perform BASIC SENSE if required.
+ */
+static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
+{
+	struct irb *irb = &cdev->private->irb;
+	struct cmd_scsw *scsw = &irb->scsw.cmd;
+
+	/* Perform BASIC SENSE if needed. */
+	if (ccw_device_accumulate_and_sense(cdev, lcirb))
+		return IO_RUNNING;
+	/* Check for halt/clear interrupt. */
+	if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
+		return IO_KILLED;
+	/* Check for path error. */
+	if (scsw->cc == 3 || scsw->pno)
+		return IO_PATH_ERROR;
+	/* Handle BASIC SENSE data. */
+	if (irb->esw.esw0.erw.cons) {
+		CIO_TRACE_EVENT(2, "sensedata");
+		CIO_HEX_EVENT(2, &cdev->private->dev_id,
+			      sizeof(struct ccw_dev_id));
+		CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
+		/* Check for command reject. */
+		if (irb->ecw[0] & SNS0_CMD_REJECT)
+			return IO_REJECTED;
+		/* Assume that unexpected SENSE data implies an error. */
+		return IO_STATUS_ERROR;
+	}
+	/* Check for channel errors. */
+	if (scsw->cstat != 0)
+		return IO_STATUS_ERROR;
+	/* Check for device errors. */
+	if (scsw->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+		return IO_STATUS_ERROR;
+	/* Check for final state. */
+	if (!(scsw->dstat & DEV_STAT_DEV_END))
+		return IO_RUNNING;
+	/* Check for other improper status. */
+	if (scsw->cc == 1 && (scsw->stctl & SCSW_STCTL_ALERT_STATUS))
+		return IO_STATUS_ERROR;
+	return IO_DONE;
+}
+
+/*
+ * Log ccw request status.
+ */
+static void ccwreq_log_status(struct ccw_device *cdev, enum io_status status)
+{
+	struct ccw_request *req = &cdev->private->req;
+	struct {
+		struct ccw_dev_id dev_id;
+		u16 retries;
+		u8 lpm;
+		u8 status;
+	}  __attribute__ ((packed)) data;
+	data.dev_id	= cdev->private->dev_id;
+	data.retries	= req->retries;
+	data.lpm	= req->mask;
+	data.status	= (u8) status;
+	CIO_TRACE_EVENT(2, "reqstat");
+	CIO_HEX_EVENT(2, &data, sizeof(data));
+}
+
+/**
+ * ccw_request_handler - interrupt handler for I/O request procedure.
+ * @cdev: ccw device
+ *
+ * Handle interrupt during I/O request procedure.
+ */
+void ccw_request_handler(struct ccw_device *cdev)
+{
+	struct ccw_request *req = &cdev->private->req;
+	struct irb *irb = (struct irb *) __LC_IRB;
+	enum io_status status;
+	int rc = -EOPNOTSUPP;
+
+	/* Check status of I/O request. */
+	status = ccwreq_status(cdev, irb);
+	if (req->filter)
+		status = req->filter(cdev, req->data, irb, status);
+	if (status != IO_RUNNING)
+		ccw_device_set_timeout(cdev, 0);
+	if (status != IO_DONE && status != IO_RUNNING)
+		ccwreq_log_status(cdev, status);
+	switch (status) {
+	case IO_DONE:
+		break;
+	case IO_RUNNING:
+		return;
+	case IO_REJECTED:
+		goto err;
+	case IO_PATH_ERROR:
+		goto out_next_path;
+	case IO_STATUS_ERROR:
+		goto out_restart;
+	case IO_KILLED:
+		/* Check if request was cancelled on purpose. */
+		if (req->cancel) {
+			rc = -EIO;
+			goto err;
+		}
+		goto out_restart;
+	}
+	/* Check back with request initiator. */
+	if (!req->check)
+		goto out;
+	switch (req->check(cdev, req->data)) {
+	case 0:
+		break;
+	case -EAGAIN:
+		goto out_restart;
+	case -EACCES:
+		goto out_next_path;
+	default:
+		goto err;
+	}
+out:
+	ccwreq_stop(cdev, 0);
+	return;
+
+out_next_path:
+	/* Try next path and restart I/O. */
+	if (!ccwreq_next_path(cdev)) {
+		rc = -EACCES;
+		goto err;
+	}
+out_restart:
+	/* Restart. */
+	ccwreq_do(cdev);
+	return;
+err:
+	ccwreq_stop(cdev, rc);
+}
+
+
+/**
+ * ccw_request_timeout - timeout handler for I/O request procedure
+ * @cdev: ccw device
+ *
+ * Handle timeout during I/O request procedure.
+ */
+void ccw_request_timeout(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+	int rc;
+
+	if (!ccwreq_next_path(cdev)) {
+		/* set the final return code for this request */
+		req->drc = -ETIME;
+	}
+	rc = cio_clear(sch);
+	if (rc)
+		goto err;
+	return;
+
+err:
+	ccwreq_stop(cdev, rc);
+}
+
+/**
+ * ccw_request_notoper - notoper handler for I/O request procedure
+ * @cdev: ccw device
+ *
+ * Handle timeout during I/O request procedure.
+ */
+void ccw_request_notoper(struct ccw_device *cdev)
+{
+	ccwreq_stop(cdev, -ENODEV);
+}
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
@@ -98,6 +98,14 @@
 int ccw_device_accumulate_and_sense(struct ccw_device *, struct irb *);
 int ccw_device_do_sense(struct ccw_device *, struct irb *);
 
+/* Function prototype for internal request handling. */
+int lpm_adjust(int lpm, int mask);
+void ccw_request_start(struct ccw_device *);
+int ccw_request_cancel(struct ccw_device *cdev);
+void ccw_request_handler(struct ccw_device *cdev);
+void ccw_request_timeout(struct ccw_device *cdev);
+void ccw_request_notoper(struct ccw_device *cdev);
+
 /* Function prototypes for sense id stuff. */
 void ccw_device_sense_id_start(struct ccw_device *);
 void ccw_device_sense_id_irq(struct ccw_device *, enum dev_event);
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:18.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:20.000000000 +0100
@@ -1,7 +1,10 @@
 #ifndef S390_IO_SCH_H
 #define S390_IO_SCH_H
 
+#include <linux/types.h>
 #include <asm/schid.h>
+#include <asm/ccwdev.h>
+#include "css.h"
 
 /*
  * command-mode operation request block
@@ -68,6 +71,52 @@
 #define MAX_CIWS 8
 
 /*
+ * Possible status values for a CCW request's I/O.
+ */
+enum io_status {
+	IO_DONE,
+	IO_RUNNING,
+	IO_STATUS_ERROR,
+	IO_PATH_ERROR,
+	IO_REJECTED,
+	IO_KILLED
+};
+
+/**
+ * ccw_request - Internal CCW request.
+ * @cp: channel program to start
+ * @timeout: maximum allowable time in jiffies between start I/O and interrupt
+ * @maxretries: number of retries per I/O operation and path
+ * @lpm: mask of paths to use
+ * @check: optional callback that determines if results are final
+ * @filter: optional callback to adjust request status based on IRB data
+ * @callback: final callback
+ * @data: user-defined pointer passed to all callbacks
+ * @mask: current path mask
+ * @retries: current number of retries
+ * @drc: delayed return code
+ * @cancel: non-zero if request was cancelled
+ * @done: non-zero if request was finished
+ */
+struct ccw_request {
+	struct ccw1 *cp;
+	unsigned long timeout;
+	u16 maxretries;
+	u8 lpm;
+	int (*check)(struct ccw_device *, void *);
+	enum io_status (*filter)(struct ccw_device *, void *, struct irb *,
+				 enum io_status);
+	void (*callback)(struct ccw_device *, void *, int);
+	void *data;
+	/* These fields are used internally. */
+	u8 mask;
+	u16 retries;
+	int drc;
+	int cancel:1;
+	int done:1;
+} __attribute__((packed));
+
+/*
  * sense-id response buffer layout
  */
 struct senseid {
@@ -99,6 +148,7 @@
 	unsigned long registered;
 	struct ccw_dev_id dev_id;	/* device id */
 	struct subchannel_id schid;	/* subchannel number */
+	struct ccw_request req;		/* internal I/O request */
 	u8 imask;		/* lpm mask for SNID/SID/SPGID */
 	int iretry;		/* retry counter SNID/SID/SPGID */
 	struct {
Index: quilt-2.6/drivers/s390/cio/Makefile
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/Makefile	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/Makefile	2009-11-13 16:08:20.000000000 +0100
@@ -3,7 +3,7 @@
 #
 
 obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
-	fcx.o itcw.o crw.o
+	fcx.o itcw.o crw.o ccwreq.o
 ccw_device-objs += device.o device_fsm.o device_ops.o
 ccw_device-objs += device_id.o device_pgid.o device_status.o
 obj-y += ccw_device.o cmf.o

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 37/52] [PATCH] cio: use ccw request infrastructure for sense id
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (35 preceding siblings ...)
  2009-11-13 15:09 ` [patch 36/52] [PATCH] cio: consistent infrastructure for internal I/O requests Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 38/52] [PATCH] cio: use ccw request infrastructure for pgid Martin Schwidefsky
                   ` (15 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 136-cio-internal-senseid.diff --]
[-- Type: text/plain, Size: 18630 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Use the newly introduced ccw request infrastructure to implement
the sense id operation.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.h     |    1 
 drivers/s390/cio/device_fsm.c |   66 +------
 drivers/s390/cio/device_id.c  |  371 +++++++++++++++---------------------------
 3 files changed, 152 insertions(+), 286 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:19.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:20.000000000 +0100
@@ -229,7 +229,6 @@
 
 	sch = to_subchannel(cdev->dev.parent);
 
-	ccw_device_set_timeout(cdev, 0);
 	cio_disable_subchannel(sch);
 	/*
 	 * Now that we tried recognition, we have performed device selection
@@ -263,22 +262,10 @@
 	}
 	switch (state) {
 	case DEV_STATE_NOT_OPER:
-		CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
-			      "subchannel 0.%x.%04x\n",
-			      cdev->private->dev_id.devno,
-			      sch->schid.ssid, sch->schid.sch_no);
 		break;
 	case DEV_STATE_OFFLINE:
 		if (!cdev->online) {
 			ccw_device_update_sense_data(cdev);
-			/* Issue device info message. */
-			CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
-				      "CU  Type/Mod = %04X/%02X, Dev Type/Mod "
-				      "= %04X/%02X\n",
-				      cdev->private->dev_id.ssid,
-				      cdev->private->dev_id.devno,
-				      cdev->id.cu_type, cdev->id.cu_model,
-				      cdev->id.dev_type, cdev->id.dev_model);
 			break;
 		}
 		cdev->private->state = DEV_STATE_OFFLINE;
@@ -293,10 +280,6 @@
 		}
 		return;
 	case DEV_STATE_BOXED:
-		CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
-			      " subchannel 0.%x.%04x\n",
-			      cdev->private->dev_id.devno,
-			      sch->schid.ssid, sch->schid.sch_no);
 		if (cdev->id.cu_type != 0) { /* device was recognized before */
 			cdev->private->flags.recog_done = 1;
 			cdev->private->state = DEV_STATE_BOXED;
@@ -520,27 +503,25 @@
 }
 
 /*
- * Handle timeout in device recognition.
+ * Handle events for states that use the ccw request infrastructure.
  */
-static void
-ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e)
 {
-	int ret;
-
-	ret = ccw_device_cancel_halt_clear(cdev);
-	switch (ret) {
-	case 0:
-		ccw_device_recog_done(cdev, DEV_STATE_BOXED);
+	switch (e) {
+	case DEV_EVENT_NOTOPER:
+		ccw_request_notoper(cdev);
 		break;
-	case -ENODEV:
-		ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
+	case DEV_EVENT_INTERRUPT:
+		ccw_request_handler(cdev);
+		break;
+	case DEV_EVENT_TIMEOUT:
+		ccw_request_timeout(cdev);
 		break;
 	default:
-		ccw_device_set_timeout(cdev, 3*HZ);
+		break;
 	}
 }
 
-
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
@@ -713,15 +694,6 @@
 }
 
 /*
- * Handle not oper event in device recognition.
- */
-static void
-ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
-}
-
-/*
  * Handle not operational event in non-special state.
  */
 static void ccw_device_generic_notoper(struct ccw_device *cdev,
@@ -1015,10 +987,6 @@
 	if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		return;
-
-	/* After 60s the device recognition is considered to have failed. */
-	ccw_device_set_timeout(cdev, 60*HZ);
-
 	cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID;
 	ccw_device_sense_id_start(cdev);
 }
@@ -1141,9 +1109,9 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_SENSE_ID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_recog_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_sense_id_irq,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_recog_timeout,
+		[DEV_EVENT_NOTOPER]	= ccw_device_request_event,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_request_event,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_request_event,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_OFFLINE] = {
@@ -1209,9 +1177,9 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_start_id,
 	},
 	[DEV_STATE_DISCONNECTED_SENSE_ID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_recog_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_sense_id_irq,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_recog_timeout,
+		[DEV_EVENT_NOTOPER]	= ccw_device_request_event,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_request_event,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_request_event,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_CMFCHANGE] = {
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
@@ -108,7 +108,6 @@
 
 /* Function prototypes for sense id stuff. */
 void ccw_device_sense_id_start(struct ccw_device *);
-void ccw_device_sense_id_irq(struct ccw_device *, enum dev_event);
 void ccw_device_sense_id_done(struct ccw_device *, int);
 
 /* Function prototypes for path grouping stuff. */
Index: quilt-2.6/drivers/s390/cio/device_id.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_id.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_id.c	2009-11-13 16:08:20.000000000 +0100
@@ -1,40 +1,39 @@
 /*
- * drivers/s390/cio/device_id.c
+ *  CCW device SENSE ID I/O handling.
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *			 IBM Corporation
- *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
- *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- * Sense ID functions.
+ *    Copyright IBM Corp. 2002,2009
+ *    Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
-
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
 #include <asm/ccwdev.h>
-#include <asm/delay.h>
+#include <asm/setup.h>
 #include <asm/cio.h>
-#include <asm/lowcore.h>
 #include <asm/diag.h>
 
 #include "cio.h"
 #include "cio_debug.h"
-#include "css.h"
 #include "device.h"
-#include "ioasm.h"
 #include "io_sch.h"
 
+#define SENSE_ID_RETRIES	5
+#define SENSE_ID_TIMEOUT	(10 * HZ)
+#define SENSE_ID_MIN_LEN	4
+#define SENSE_ID_BASIC_LEN	7
+
 /**
- * vm_vdev_to_cu_type - Convert vm virtual device into control unit type
- *			for certain devices.
- * @class: virtual device class
- * @type: virtual device type
+ * diag210_to_senseid - convert diag 0x210 data to sense id information
+ * @senseid: sense id
+ * @diag: diag 0x210 data
  *
- * Returns control unit type if a match was made or %0xffff otherwise.
+ * Return 0 on success, non-zero otherwise.
  */
-static int vm_vdev_to_cu_type(int class, int type)
+static int diag210_to_senseid(struct senseid *senseid, struct diag210 *diag)
 {
 	static struct {
 		int class, type, cu_type;
@@ -71,253 +70,153 @@
 	};
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
-		if (class == vm_devices[i].class && type == vm_devices[i].type)
-			return vm_devices[i].cu_type;
+	/* Special case for osa devices. */
+	if (diag->vrdcvcla == 0x02 && diag->vrdcvtyp == 0x20) {
+		senseid->cu_type = 0x3088;
+		senseid->cu_model = 0x60;
+		senseid->reserved = 0xff;
+		return 0;
+	}
+	for (i = 0; i < ARRAY_SIZE(vm_devices); i++) {
+		if (diag->vrdcvcla == vm_devices[i].class &&
+		    diag->vrdcvtyp == vm_devices[i].type) {
+			senseid->cu_type = vm_devices[i].cu_type;
+			senseid->reserved = 0xff;
+			return 0;
+		}
+	}
 
-	return 0xffff;
+	return -ENODEV;
 }
 
 /**
- * diag_get_dev_info - retrieve device information via DIAG X'210'
- * @devno: device number
- * @ps: pointer to sense ID data area
+ * diag_get_dev_info - retrieve device information via diag 0x210
+ * @cdev: ccw device
  *
  * Returns zero on success, non-zero otherwise.
  */
-static int diag_get_dev_info(u16 devno, struct senseid *ps)
+static int diag210_get_dev_info(struct ccw_device *cdev)
 {
+	struct ccw_dev_id *dev_id = &cdev->private->dev_id;
+	struct senseid *senseid = &cdev->private->senseid;
 	struct diag210 diag_data;
-	int ccode;
-
-	CIO_TRACE_EVENT (4, "VMvdinf");
-
-	diag_data = (struct diag210) {
-		.vrdcdvno = devno,
-		.vrdclen = sizeof (diag_data),
-	};
-
-	ccode = diag210 (&diag_data);
-	if ((ccode == 0) || (ccode == 2)) {
-		ps->reserved = 0xff;
-
-		/* Special case for osa devices. */
-		if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) {
-			ps->cu_type = 0x3088;
-			ps->cu_model = 0x60;
-			return 0;
-		}
-		ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla,
-						diag_data.vrdcvtyp);
-		if (ps->cu_type != 0xffff)
-			return 0;
-	}
-
-	CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
-		      "vdev class : %02X, vdev type : %04X \n ...  "
-		      "rdev class : %02X, rdev type : %04X, "
-		      "rdev model: %02X\n",
-		      devno, ccode,
-		      diag_data.vrdcvcla, diag_data.vrdcvtyp,
-		      diag_data.vrdcrccl, diag_data.vrdccrty,
-		      diag_data.vrdccrmd);
+	int rc;
 
+	if (dev_id->ssid != 0)
+		return -ENODEV;
+	memset(&diag_data, 0, sizeof(diag_data));
+	diag_data.vrdcdvno	= dev_id->devno;
+	diag_data.vrdclen	= sizeof(diag_data);
+	rc = diag210(&diag_data);
+	CIO_TRACE_EVENT(4, "diag210");
+	CIO_HEX_EVENT(4, &rc, sizeof(rc));
+	CIO_HEX_EVENT(4, &diag_data, sizeof(diag_data));
+	if (rc != 0 && rc != 2)
+		goto err_failed;
+	if (diag210_to_senseid(senseid, &diag_data))
+		goto err_unknown;
+	return 0;
+
+err_unknown:
+	CIO_MSG_EVENT(0, "snsid: device 0.%x.%04x: unknown diag210 data\n",
+		      dev_id->ssid, dev_id->devno);
+	return -ENODEV;
+err_failed:
+	CIO_MSG_EVENT(0, "snsid: device 0.%x.%04x: diag210 failed (rc=%d)\n",
+		      dev_id->ssid, dev_id->devno, rc);
 	return -ENODEV;
 }
 
 /*
- * Start Sense ID helper function.
- * Try to obtain the 'control unit'/'device type' information
- *  associated with the subchannel.
+ * Initialize SENSE ID data.
  */
-static int
-__ccw_device_sense_id_start(struct ccw_device *cdev)
-{
-	struct subchannel *sch;
-	struct ccw1 *ccw;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	/* Setup sense channel program. */
-	ccw = cdev->private->iccws;
-	ccw->cmd_code = CCW_CMD_SENSE_ID;
-	ccw->cda = (__u32) __pa (&cdev->private->senseid);
-	ccw->count = sizeof (struct senseid);
-	ccw->flags = CCW_FLAG_SLI;
-
-	/* Reset device status. */
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-
-	/* Try on every path. */
-	ret = -ENODEV;
-	while (cdev->private->imask != 0) {
-		cdev->private->senseid.cu_type = 0xFFFF;
-		if ((sch->opm & cdev->private->imask) != 0 &&
-		    cdev->private->iretry > 0) {
-			cdev->private->iretry--;
-			/* Reset internal retry indication. */
-			cdev->private->flags.intretry = 0;
-			ret = cio_start (sch, cdev->private->iccws,
-					 cdev->private->imask);
-			/* ret is 0, -EBUSY, -EACCES or -ENODEV */
-			if (ret != -EACCES)
-				return ret;
-		}
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-	}
-	return ret;
-}
-
-void
-ccw_device_sense_id_start(struct ccw_device *cdev)
+static void snsid_init(struct ccw_device *cdev)
 {
-	int ret;
-
-	memset (&cdev->private->senseid, 0, sizeof (struct senseid));
-	cdev->private->imask = 0x80;
-	cdev->private->iretry = 5;
-	ret = __ccw_device_sense_id_start(cdev);
-	if (ret && ret != -EBUSY)
-		ccw_device_sense_id_done(cdev, ret);
+	cdev->private->flags.esid = 0;
+	memset(&cdev->private->senseid, 0, sizeof(cdev->private->senseid));
+	cdev->private->senseid.cu_type = 0xffff;
 }
 
 /*
- * Called from interrupt context to check if a valid answer
- * to Sense ID was received.
+ * Check for complete SENSE ID data.
  */
-static int
-ccw_device_check_sense_id(struct ccw_device *cdev)
+static int snsid_check(struct ccw_device *cdev, void *data)
 {
-	struct subchannel *sch;
-	struct irb *irb;
+	struct cmd_scsw *scsw = &cdev->private->irb.scsw.cmd;
+	int len = sizeof(struct senseid) - scsw->count;
 
-	sch = to_subchannel(cdev->dev.parent);
-	irb = &cdev->private->irb;
-
-	/* Check the error cases. */
-	if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
-		/* Retry Sense ID if requested. */
-		if (cdev->private->flags.intretry) {
-			cdev->private->flags.intretry = 0;
-			return -EAGAIN;
-		}
-		return -ETIME;
-	}
-	if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) {
-		/*
-		 * if the device doesn't support the SenseID
-		 *  command further retries wouldn't help ...
-		 * NB: We don't check here for intervention required like we
-		 *     did before, because tape devices with no tape inserted
-		 *     may present this status *in conjunction with* the
-		 *     sense id information. So, for intervention required,
-		 *     we use the "whack it until it talks" strategy...
-		 */
-		CIO_MSG_EVENT(0, "SenseID : device %04x on Subchannel "
-			      "0.%x.%04x reports cmd reject\n",
-			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no);
+	/* Check for incomplete SENSE ID data. */
+	if (len < SENSE_ID_MIN_LEN)
+		goto out_restart;
+	if (cdev->private->senseid.cu_type == 0xffff)
+		goto out_restart;
+	/* Check for incompatible SENSE ID data. */
+	if (cdev->private->senseid.reserved != 0xff)
 		return -EOPNOTSUPP;
-	}
-	if (irb->esw.esw0.erw.cons) {
-		CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, "
-			      "lpum %02X, cnt %02d, sns :"
-			      " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno,
-			      irb->esw.esw0.sublog.lpum,
-			      irb->esw.esw0.erw.scnt,
-			      irb->ecw[0], irb->ecw[1],
-			      irb->ecw[2], irb->ecw[3],
-			      irb->ecw[4], irb->ecw[5],
-			      irb->ecw[6], irb->ecw[7]);
-		return -EAGAIN;
-	}
-	if (irb->scsw.cmd.cc == 3) {
-		u8 lpm;
-
-		lpm = to_io_private(sch)->orb.cmd.lpm;
-		if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
-			CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x "
-				      "on subchannel 0.%x.%04x is "
-				      "'not operational'\n", lpm,
-				      cdev->private->dev_id.devno,
-				      sch->schid.ssid, sch->schid.sch_no);
-		return -EACCES;
-	}
-
-	/* Did we get a proper answer ? */
-	if (irb->scsw.cmd.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
-	    cdev->private->senseid.reserved == 0xFF) {
-		if (irb->scsw.cmd.count < sizeof(struct senseid) - 8)
-			cdev->private->flags.esid = 1;
-		return 0; /* Success */
-	}
+	/* Check for extended-identification information. */
+	if (len > SENSE_ID_BASIC_LEN)
+		cdev->private->flags.esid = 1;
+	return 0;
 
-	/* Hmm, whatever happened, try again. */
-	CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
-		      "subchannel 0.%x.%04x returns status %02X%02X\n",
-		      cdev->private->dev_id.devno, sch->schid.ssid,
-		      sch->schid.sch_no,
-		      irb->scsw.cmd.dstat, irb->scsw.cmd.cstat);
+out_restart:
+	snsid_init(cdev);
 	return -EAGAIN;
 }
 
 /*
- * Got interrupt for Sense ID.
+ * Process SENSE ID request result.
  */
-void
-ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void snsid_callback(struct ccw_device *cdev, void *data, int rc)
 {
-	struct subchannel *sch;
-	struct irb *irb;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	irb = (struct irb *) __LC_IRB;
-	/* Retry sense id, if needed. */
-	if (irb->scsw.cmd.stctl ==
-	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if ((irb->scsw.cmd.cc == 1) || !irb->scsw.cmd.actl) {
-			ret = __ccw_device_sense_id_start(cdev);
-			if (ret && ret != -EBUSY)
-				ccw_device_sense_id_done(cdev, ret);
+	struct ccw_dev_id *id = &cdev->private->dev_id;
+	struct senseid *senseid = &cdev->private->senseid;
+	int vm = 0;
+
+	if (rc && MACHINE_IS_VM) {
+		/* Try diag 0x210 fallback on z/VM. */
+		snsid_init(cdev);
+		if (diag210_get_dev_info(cdev) == 0) {
+			rc = 0;
+			vm = 1;
 		}
-		return;
 	}
-	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
-		return;
-	ret = ccw_device_check_sense_id(cdev);
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-	switch (ret) {
-	/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN or -EACCES */
-	case 0:			/* Sense id succeeded. */
-	case -ETIME:		/* Sense id stopped by timeout. */
-		ccw_device_sense_id_done(cdev, ret);
-		break;
-	case -EACCES:		/* channel is not operational. */
-		sch->lpm &= ~cdev->private->imask;
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-		/* fall through. */
-	case -EAGAIN:		/* try again. */
-		ret = __ccw_device_sense_id_start(cdev);
-		if (ret == 0 || ret == -EBUSY)
-			break;
-		/* fall through. */
-	default:		/* Sense ID failed. Try asking VM. */
-		if (MACHINE_IS_VM)
-			ret = diag_get_dev_info(cdev->private->dev_id.devno,
-						&cdev->private->senseid);
-		else
-			/*
-			 * If we can't couldn't identify the device type we
-			 *  consider the device "not operational".
-			 */
-			ret = -ENODEV;
+	CIO_MSG_EVENT(2, "snsid: device 0.%x.%04x: rc=%d %04x/%02x "
+		      "%04x/%02x%s\n", id->ssid, id->devno, rc,
+		      senseid->cu_type, senseid->cu_model, senseid->dev_type,
+		      senseid->dev_model, vm ? " (diag210)" : "");
+	ccw_device_sense_id_done(cdev, rc);
+}
 
-		ccw_device_sense_id_done(cdev, ret);
-		break;
-	}
+/**
+ * ccw_device_sense_id_start - perform SENSE ID
+ * @cdev: ccw device
+ *
+ * Execute a SENSE ID channel program on @cdev to update its sense id
+ * information. When finished, call ccw_device_sense_id_done with a
+ * return code specifying the result.
+ */
+void ccw_device_sense_id_start(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+	struct ccw1 *cp = cdev->private->iccws;
+
+	CIO_TRACE_EVENT(4, "snsid");
+	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+	/* Data setup. */
+	snsid_init(cdev);
+	/* Channel program setup. */
+	cp->cmd_code	= CCW_CMD_SENSE_ID;
+	cp->cda		= (u32) (addr_t) &cdev->private->senseid;
+	cp->count	= sizeof(struct senseid);
+	cp->flags	= CCW_FLAG_SLI;
+	/* Request setup. */
+	memset(req, 0, sizeof(*req));
+	req->cp		= cp;
+	req->timeout	= SENSE_ID_TIMEOUT;
+	req->maxretries	= SENSE_ID_RETRIES;
+	req->lpm	= sch->schib.pmcw.pam & sch->opm;
+	req->check	= snsid_check;
+	req->callback	= snsid_callback;
+	ccw_request_start(cdev);
 }

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 38/52] [PATCH] cio: use ccw request infrastructure for pgid
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (36 preceding siblings ...)
  2009-11-13 15:09 ` [patch 37/52] [PATCH] cio: use ccw request infrastructure for sense id Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 39/52] [PATCH] cio: allow setting not-operational devices offline Martin Schwidefsky
                   ` (14 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 137-cio-internal-pgid.diff --]
[-- Type: text/plain, Size: 36745 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Use the newly introduced ccw request infrastructure to implement
pgid related operations: sense pgid, set pgid and disband pg.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c      |    3 
 drivers/s390/cio/device.h      |    3 
 drivers/s390/cio/device_fsm.c  |  100 ----
 drivers/s390/cio/device_pgid.c |  868 +++++++++++++++++------------------------
 drivers/s390/cio/io_sch.h      |    5 
 5 files changed, 379 insertions(+), 600 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:19.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:20.000000000 +0100
@@ -957,9 +957,6 @@
 {
 	memset(&sch->config, 0, sizeof(sch->config));
 	sch->config.csense = 1;
-	/* Use subchannel mp mode when there is more than 1 installed CHPID. */
-	if ((sch->schib.pmcw.pim & (sch->schib.pmcw.pim - 1)) != 0)
-		sch->config.mp = 1;
 }
 
 static void io_subchannel_init_fields(struct subchannel *sch)
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:20.000000000 +0100
@@ -394,58 +394,6 @@
 	wake_up(&cdev->private->wait_q);
 }
 
-static int cmp_pgid(struct pgid *p1, struct pgid *p2)
-{
-	char *c1;
-	char *c2;
-
-	c1 = (char *)p1;
-	c2 = (char *)p2;
-
-	return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
-}
-
-static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
-{
-	int i;
-	int last;
-
-	last = 0;
-	for (i = 0; i < 8; i++) {
-		if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
-			/* No PGID yet */
-			continue;
-		if (cdev->private->pgid[last].inf.ps.state1 ==
-		    SNID_STATE1_RESET) {
-			/* First non-zero PGID */
-			last = i;
-			continue;
-		}
-		if (cmp_pgid(&cdev->private->pgid[i],
-			     &cdev->private->pgid[last]) == 0)
-			/* Non-conflicting PGIDs */
-			continue;
-
-		/* PGID mismatch, can't pathgroup. */
-		CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
-			      "0.%x.%04x, can't pathgroup\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno);
-		cdev->private->options.pgroup = 0;
-		return;
-	}
-	if (cdev->private->pgid[last].inf.ps.state1 ==
-	    SNID_STATE1_RESET)
-		/* No previous pgid found */
-		memcpy(&cdev->private->pgid[0],
-		       &channel_subsystems[0]->global_pgid,
-		       sizeof(struct pgid));
-	else
-		/* Use existing pgid */
-		memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
-		       sizeof(struct pgid));
-}
-
 /*
  * Function called from device_pgid.c after sense path ground has completed.
  */
@@ -457,12 +405,8 @@
 	sch = to_subchannel(cdev->dev.parent);
 	switch (err) {
 	case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
-		cdev->private->options.pgroup = 0;
-		break;
 	case 0: /* success */
 	case -EACCES: /* partial success, some paths not operational */
-		/* Check if all pgids are equal or 0. */
-		__ccw_device_get_common_pgid(cdev);
 		break;
 	case -ETIME:		/* Sense path group id stopped by timeout. */
 	case -EUSERS:		/* device is reserved for someone else. */
@@ -474,7 +418,6 @@
 	}
 	/* Start Path Group verification. */
 	cdev->private->state = DEV_STATE_VERIFY;
-	cdev->private->flags.doverify = 0;
 	ccw_device_verify_start(cdev);
 }
 
@@ -537,7 +480,6 @@
 	sch->lpm = sch->vpm;
 	/* Repeat path verification? */
 	if (cdev->private->flags.doverify) {
-		cdev->private->flags.doverify = 0;
 		ccw_device_verify_start(cdev);
 		return;
 	}
@@ -602,7 +544,6 @@
 	if (!cdev->private->options.pgroup) {
 		/* Start initial path verification. */
 		cdev->private->state = DEV_STATE_VERIFY;
-		cdev->private->flags.doverify = 0;
 		ccw_device_verify_start(cdev);
 		return 0;
 	}
@@ -624,7 +565,6 @@
 		break;
 	default:
 		cdev->private->flags.donotify = 0;
-		dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -673,27 +613,6 @@
 }
 
 /*
- * Handle timeout in device online/offline process.
- */
-static void
-ccw_device_onoff_timeout(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	int ret;
-
-	ret = ccw_device_cancel_halt_clear(cdev);
-	switch (ret) {
-	case 0:
-		ccw_device_done(cdev, DEV_STATE_BOXED);
-		break;
-	case -ENODEV:
-		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
-		break;
-	default:
-		ccw_device_set_timeout(cdev, 3*HZ);
-	}
-}
-
-/*
  * Handle not operational event in non-special state.
  */
 static void ccw_device_generic_notoper(struct ccw_device *cdev,
@@ -751,7 +670,6 @@
 	}
 	/* Device is idle, we can do the path verification. */
 	cdev->private->state = DEV_STATE_VERIFY;
-	cdev->private->flags.doverify = 0;
 	ccw_device_verify_start(cdev);
 }
 
@@ -1103,9 +1021,9 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_SENSE_PGID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_sense_pgid_irq,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
+		[DEV_EVENT_NOTOPER]	= ccw_device_request_event,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_request_event,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_request_event,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_SENSE_ID] = {
@@ -1121,9 +1039,9 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_offline_verify,
 	},
 	[DEV_STATE_VERIFY] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_verify_irq,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
+		[DEV_EVENT_NOTOPER]	= ccw_device_request_event,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_request_event,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_request_event,
 		[DEV_EVENT_VERIFY]	= ccw_device_delay_verify,
 	},
 	[DEV_STATE_ONLINE] = {
@@ -1139,9 +1057,9 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_online_verify,
 	},
 	[DEV_STATE_DISBAND_PGID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_disband_irq,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
+		[DEV_EVENT_NOTOPER]	= ccw_device_request_event,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_request_event,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_request_event,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_BOXED] = {
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
@@ -112,15 +112,12 @@
 
 /* Function prototypes for path grouping stuff. */
 void ccw_device_sense_pgid_start(struct ccw_device *);
-void ccw_device_sense_pgid_irq(struct ccw_device *, enum dev_event);
 void ccw_device_sense_pgid_done(struct ccw_device *, int);
 
 void ccw_device_verify_start(struct ccw_device *);
-void ccw_device_verify_irq(struct ccw_device *, enum dev_event);
 void ccw_device_verify_done(struct ccw_device *, int);
 
 void ccw_device_disband_start(struct ccw_device *);
-void ccw_device_disband_irq(struct ccw_device *, enum dev_event);
 void ccw_device_disband_done(struct ccw_device *, int);
 
 int ccw_device_call_handler(struct ccw_device *);
Index: quilt-2.6/drivers/s390/cio/device_pgid.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:19.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:20.000000000 +0100
@@ -1,594 +1,460 @@
 /*
- * drivers/s390/cio/device_pgid.c
+ *  CCW device PGID and path verification I/O handling.
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *			 IBM Corporation
- *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
- *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- * Path Group ID functions.
+ *    Copyright IBM Corp. 2002,2009
+ *    Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
-
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
-#include <asm/delay.h>
-#include <asm/lowcore.h>
 
 #include "cio.h"
 #include "cio_debug.h"
-#include "css.h"
 #include "device.h"
-#include "ioasm.h"
 #include "io_sch.h"
 
+#define PGID_RETRIES	5
+#define PGID_TIMEOUT	(10 * HZ)
+
 /*
- * Helper function called from interrupt context to decide whether an
- * operation should be tried again.
+ * Process path verification data and report result.
  */
-static int __ccw_device_should_retry(union scsw *scsw)
+static void verify_done(struct ccw_device *cdev, int rc)
 {
-	/* CC is only valid if start function bit is set. */
-	if ((scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && scsw->cmd.cc == 1)
-		return 1;
-	/* No more activity. For sense and set PGID we stubbornly try again. */
-	if (!scsw->cmd.actl)
-		return 1;
-	return 0;
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_dev_id *id = &cdev->private->dev_id;
+	int mpath = !cdev->private->flags.pgid_single;
+	int pgroup = cdev->private->options.pgroup;
+
+	if (rc)
+		goto out;
+	/* Ensure consistent multipathing state at device and channel. */
+	if (sch->config.mp != mpath) {
+		sch->config.mp = mpath;
+		rc = cio_commit_config(sch);
+	}
+out:
+	CIO_MSG_EVENT(2, "vrfy: device 0.%x.%04x: rc=%d pgroup=%d mpath=%d "
+			 "vpm=%02x\n", id->ssid, id->devno, rc, pgroup, mpath,
+			 sch->vpm);
+	ccw_device_verify_done(cdev, rc);
 }
 
 /*
- * Start Sense Path Group ID helper function. Used in ccw_device_recog
- * and ccw_device_sense_pgid.
+ * Create channel program to perform a NOOP.
  */
-static int
-__ccw_device_sense_pgid_start(struct ccw_device *cdev)
+static void nop_build_cp(struct ccw_device *cdev)
 {
-	struct subchannel *sch;
-	struct ccw1 *ccw;
-	int ret;
-	int i;
-
-	sch = to_subchannel(cdev->dev.parent);
-	/* Return if we already checked on all paths. */
-	if (cdev->private->imask == 0)
-		return (sch->lpm == 0) ? -ENODEV : -EACCES;
-	i = 8 - ffs(cdev->private->imask);
-
-	/* Setup sense path group id channel program. */
-	ccw = cdev->private->iccws;
-	ccw->cmd_code = CCW_CMD_SENSE_PGID;
-	ccw->count = sizeof (struct pgid);
-	ccw->flags = CCW_FLAG_SLI;
-
-	/* Reset device status. */
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-	/* Try on every path. */
-	ret = -ENODEV;
-	while (cdev->private->imask != 0) {
-		/* Try every path multiple times. */
-		ccw->cda = (__u32) __pa (&cdev->private->pgid[i]);
-		if (cdev->private->iretry > 0) {
-			cdev->private->iretry--;
-			/* Reset internal retry indication. */
-			cdev->private->flags.intretry = 0;
-			ret = cio_start (sch, cdev->private->iccws, 
-					 cdev->private->imask);
-			/* ret is 0, -EBUSY, -EACCES or -ENODEV */
-			if (ret != -EACCES)
-				return ret;
-			CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel "
-				      "0.%x.%04x, lpm %02X, became 'not "
-				      "operational'\n",
-				      cdev->private->dev_id.devno,
-				      sch->schid.ssid,
-				      sch->schid.sch_no, cdev->private->imask);
+	struct ccw_request *req = &cdev->private->req;
+	struct ccw1 *cp = cdev->private->iccws;
 
-		}
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-		i++;
-	}
-
-	return ret;
+	cp->cmd_code	= CCW_CMD_NOOP;
+	cp->cda		= 0;
+	cp->count	= 0;
+	cp->flags	= CCW_FLAG_SLI;
+	req->cp		= cp;
 }
 
-void
-ccw_device_sense_pgid_start(struct ccw_device *cdev)
+/*
+ * Perform NOOP on a single path.
+ */
+static void nop_do(struct ccw_device *cdev)
 {
-	int ret;
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
 
-	/* Set a timeout of 60s */
-	ccw_device_set_timeout(cdev, 60*HZ);
+	/* Adjust lpm. */
+	req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & sch->opm);
+	if (!req->lpm)
+		goto out_nopath;
+	nop_build_cp(cdev);
+	ccw_request_start(cdev);
+	return;
 
-	cdev->private->state = DEV_STATE_SENSE_PGID;
-	cdev->private->imask = 0x80;
-	cdev->private->iretry = 5;
-	memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid));
-	ret = __ccw_device_sense_pgid_start(cdev);
-	if (ret && ret != -EBUSY)
-		ccw_device_sense_pgid_done(cdev, ret);
+out_nopath:
+	verify_done(cdev, sch->vpm ? 0 : -EACCES);
 }
 
 /*
- * Called from interrupt context to check if a valid answer
- * to Sense Path Group ID was received.
+ * Adjust NOOP I/O status.
  */
-static int
-__ccw_device_check_sense_pgid(struct ccw_device *cdev)
+static enum io_status nop_filter(struct ccw_device *cdev, void *data,
+				 struct irb *irb, enum io_status status)
 {
-	struct subchannel *sch;
-	struct irb *irb;
-	int i;
-
-	sch = to_subchannel(cdev->dev.parent);
-	irb = &cdev->private->irb;
-	if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
-		/* Retry Sense PGID if requested. */
-		if (cdev->private->flags.intretry) {
-			cdev->private->flags.intretry = 0;
-			return -EAGAIN;
-		}
-		return -ETIME;
-	}
-	if (irb->esw.esw0.erw.cons &&
-	    (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) {
-		/*
-		 * If the device doesn't support the Sense Path Group ID
-		 *  command further retries wouldn't help ...
-		 */
-		return -EOPNOTSUPP;
-	}
-	if (irb->esw.esw0.erw.cons) {
-		CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, "
-			      "lpum %02X, cnt %02d, sns : "
-			      "%02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno,
-			      irb->esw.esw0.sublog.lpum,
-			      irb->esw.esw0.erw.scnt,
-			      irb->ecw[0], irb->ecw[1],
-			      irb->ecw[2], irb->ecw[3],
-			      irb->ecw[4], irb->ecw[5],
-			      irb->ecw[6], irb->ecw[7]);
-		return -EAGAIN;
-	}
-	if (irb->scsw.cmd.cc == 3) {
-		u8 lpm;
-
-		lpm = to_io_private(sch)->orb.cmd.lpm;
-		CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x,"
-			      " lpm %02X, became 'not operational'\n",
-			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no, lpm);
-		return -EACCES;
-	}
-	i = 8 - ffs(cdev->private->imask);
-	if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
-		CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
-			      "is reserved by someone else\n",
-			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no);
-		return -EUSERS;
-	}
-	return 0;
+	/* Only subchannel status might indicate a path error. */
+	if (status == IO_STATUS_ERROR && irb->scsw.cmd.cstat == 0)
+		return IO_DONE;
+	return status;
 }
 
 /*
- * Got interrupt for Sense Path Group ID.
+ * Process NOOP request result for a single path.
  */
-void
-ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void nop_callback(struct ccw_device *cdev, void *data, int rc)
 {
-	struct subchannel *sch;
-	struct irb *irb;
-	int ret;
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
 
-	irb = (struct irb *) __LC_IRB;
+	if (rc == 0)
+		sch->vpm |= req->lpm;
+	else if (rc != -EACCES)
+		goto err;
+	req->lpm >>= 1;
+	nop_do(cdev);
+	return;
 
-	if (irb->scsw.cmd.stctl ==
-	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if (__ccw_device_should_retry(&irb->scsw)) {
-			ret = __ccw_device_sense_pgid_start(cdev);
-			if (ret && ret != -EBUSY)
-				ccw_device_sense_pgid_done(cdev, ret);
-		}
-		return;
-	}
-	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
-		return;
-	sch = to_subchannel(cdev->dev.parent);
-	ret = __ccw_device_check_sense_pgid(cdev);
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-	switch (ret) {
-	/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
-	case -EOPNOTSUPP:	/* Sense Path Group ID not supported */
-		ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP);
-		break;
-	case -ETIME:		/* Sense path group id stopped by timeout. */
-		ccw_device_sense_pgid_done(cdev, -ETIME);
-		break;
-	case -EACCES:		/* channel is not operational. */
-		sch->lpm &= ~cdev->private->imask;
-		/* Fall through. */
-	case 0:			/* Sense Path Group ID successful. */
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-		/* Fall through. */
-	case -EAGAIN:		/* Try again. */
-		ret = __ccw_device_sense_pgid_start(cdev);
-		if (ret != 0 && ret != -EBUSY)
-			ccw_device_sense_pgid_done(cdev, ret);
-		break;
-	case -EUSERS:		/* device is reserved for someone else. */
-		ccw_device_sense_pgid_done(cdev, -EUSERS);
-		break;
-	}
+err:
+	verify_done(cdev, rc);
 }
 
 /*
- * Path Group ID helper function.
+ * Create channel program to perform SET PGID on a single path.
  */
-static int
-__ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
+static void spid_build_cp(struct ccw_device *cdev, u8 fn)
 {
-	struct subchannel *sch;
-	struct ccw1 *ccw;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-
-	/* Setup sense path group id channel program. */
-	cdev->private->pgid[0].inf.fc = func;
-	ccw = cdev->private->iccws;
-	if (cdev->private->flags.pgid_single)
-		cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
-	else
-		cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
-	ccw->cmd_code = CCW_CMD_SET_PGID;
-	ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
-	ccw->count = sizeof (struct pgid);
-	ccw->flags = CCW_FLAG_SLI;
-
-	/* Reset device status. */
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-
-	/* Try multiple times. */
-	ret = -EACCES;
-	if (cdev->private->iretry > 0) {
-		cdev->private->iretry--;
-		/* Reset internal retry indication. */
-		cdev->private->flags.intretry = 0;
-		ret = cio_start (sch, cdev->private->iccws,
-				 cdev->private->imask);
-		/* We expect an interrupt in case of success or busy
-		 * indication. */
-		if ((ret == 0) || (ret == -EBUSY))
-			return ret;
-	}
-	/* PGID command failed on this path. */
-	CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel "
-		      "0.%x.%04x, lpm %02X, became 'not operational'\n",
-		      cdev->private->dev_id.devno, sch->schid.ssid,
-		      sch->schid.sch_no, cdev->private->imask);
-	return ret;
+	struct ccw_request *req = &cdev->private->req;
+	struct ccw1 *cp = cdev->private->iccws;
+	int i = 8 - ffs(req->lpm);
+	struct pgid *pgid = &cdev->private->pgid[i];
+
+	pgid->inf.fc	= fn;
+	cp->cmd_code	= CCW_CMD_SET_PGID;
+	cp->cda		= (u32) (addr_t) pgid;
+	cp->count	= sizeof(*pgid);
+	cp->flags	= CCW_FLAG_SLI;
+	req->cp		= cp;
 }
 
 /*
- * Helper function to send a nop ccw down a path.
- */
-static int __ccw_device_do_nop(struct ccw_device *cdev)
-{
-	struct subchannel *sch;
-	struct ccw1 *ccw;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-
-	/* Setup nop channel program. */
-	ccw = cdev->private->iccws;
-	ccw->cmd_code = CCW_CMD_NOOP;
-	ccw->cda = 0;
-	ccw->count = 0;
-	ccw->flags = CCW_FLAG_SLI;
-
-	/* Reset device status. */
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-
-	/* Try multiple times. */
-	ret = -EACCES;
-	if (cdev->private->iretry > 0) {
-		cdev->private->iretry--;
-		/* Reset internal retry indication. */
-		cdev->private->flags.intretry = 0;
-		ret = cio_start (sch, cdev->private->iccws,
-				 cdev->private->imask);
-		/* We expect an interrupt in case of success or busy
-		 * indication. */
-		if ((ret == 0) || (ret == -EBUSY))
-			return ret;
-	}
-	/* nop command failed on this path. */
-	CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel "
-		      "0.%x.%04x, lpm %02X, became 'not operational'\n",
-		      cdev->private->dev_id.devno, sch->schid.ssid,
-		      sch->schid.sch_no, cdev->private->imask);
-	return ret;
+ * Perform establish/resign SET PGID on a single path.
+ */
+static void spid_do(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+	u8 fn;
+
+	/* Adjust lpm if paths are not set in pam. */
+	req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam);
+	if (!req->lpm)
+		goto out_nopath;
+	/* Channel program setup. */
+	if (req->lpm & sch->opm)
+		fn = SPID_FUNC_ESTABLISH;
+	else
+		fn = SPID_FUNC_RESIGN;
+	if (!cdev->private->flags.pgid_single)
+		fn |= SPID_FUNC_MULTI_PATH;
+	spid_build_cp(cdev, fn);
+	ccw_request_start(cdev);
+	return;
+
+out_nopath:
+	verify_done(cdev, sch->vpm ? 0 : -EACCES);
 }
 
+static void verify_start(struct ccw_device *cdev);
 
 /*
- * Called from interrupt context to check if a valid answer
- * to Set Path Group ID was received.
+ * Process SET PGID request result for a single path.
  */
-static int
-__ccw_device_check_pgid(struct ccw_device *cdev)
+static void spid_callback(struct ccw_device *cdev, void *data, int rc)
 {
-	struct subchannel *sch;
-	struct irb *irb;
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
 
-	sch = to_subchannel(cdev->dev.parent);
-	irb = &cdev->private->irb;
-	if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
-		/* Retry Set PGID if requested. */
-		if (cdev->private->flags.intretry) {
-			cdev->private->flags.intretry = 0;
-			return -EAGAIN;
+	switch (rc) {
+	case 0:
+		sch->vpm |= req->lpm & sch->opm;
+		break;
+	case -EACCES:
+		break;
+	case -EOPNOTSUPP:
+		if (!cdev->private->flags.pgid_single) {
+			/* Try without multipathing. */
+			cdev->private->flags.pgid_single = 1;
+			goto out_restart;
 		}
-		return -ETIME;
-	}
-	if (irb->esw.esw0.erw.cons) {
-		if (irb->ecw[0] & SNS0_CMD_REJECT)
-			return -EOPNOTSUPP;
-		/* Hmm, whatever happened, try again. */
-		CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
-			      "cnt %02d, "
-			      "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-			      cdev->private->dev_id.ssid,
-			      cdev->private->dev_id.devno,
-			      irb->esw.esw0.erw.scnt,
-			      irb->ecw[0], irb->ecw[1],
-			      irb->ecw[2], irb->ecw[3],
-			      irb->ecw[4], irb->ecw[5],
-			      irb->ecw[6], irb->ecw[7]);
-		return -EAGAIN;
-	}
-	if (irb->scsw.cmd.cc == 3) {
-		CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x,"
-			      " lpm %02X, became 'not operational'\n",
-			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no, cdev->private->imask);
-		return -EACCES;
+		/* Try without pathgrouping. */
+		cdev->private->options.pgroup = 0;
+		goto out_restart;
+	default:
+		goto err;
 	}
-	return 0;
+	req->lpm >>= 1;
+	spid_do(cdev);
+	return;
+
+out_restart:
+	verify_start(cdev);
+	return;
+err:
+	verify_done(cdev, rc);
+}
+
+static int pgid_cmp(struct pgid *p1, struct pgid *p2)
+{
+	return memcmp((char *) p1 + 1, (char *) p2 + 1,
+		      sizeof(struct pgid) - 1);
 }
 
 /*
- * Called from interrupt context to check the path status after a nop has
- * been send.
+ * Determine pathgroup state from PGID data.
  */
-static int __ccw_device_check_nop(struct ccw_device *cdev)
+static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
+			 int *mismatch, int *reserved, int *reset)
 {
-	struct subchannel *sch;
-	struct irb *irb;
+	struct pgid *pgid = &cdev->private->pgid[0];
+	struct pgid *first = NULL;
+	int lpm;
+	int i;
 
-	sch = to_subchannel(cdev->dev.parent);
-	irb = &cdev->private->irb;
-	if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
-		/* Retry NOP if requested. */
-		if (cdev->private->flags.intretry) {
-			cdev->private->flags.intretry = 0;
-			return -EAGAIN;
+	*mismatch = 0;
+	*reserved = 0;
+	*reset = 0;
+	for (i = 0, lpm = 0x80; i < 8; i++, pgid++, lpm >>= 1) {
+		if ((cdev->private->pgid_valid_mask & lpm) == 0)
+			continue;
+		if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE)
+			*reserved = 1;
+		if (pgid->inf.ps.state1 == SNID_STATE1_RESET) {
+			/* A PGID was reset. */
+			*reset = 1;
+			continue;
 		}
-		return -ETIME;
-	}
-	if (irb->scsw.cmd.cc == 3) {
-		CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x,"
-			      " lpm %02X, became 'not operational'\n",
-			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no, cdev->private->imask);
-		return -EACCES;
+		if (!first) {
+			first = pgid;
+			continue;
+		}
+		if (pgid_cmp(pgid, first) != 0)
+			*mismatch = 1;
 	}
-	return 0;
+	if (!first)
+		first = &channel_subsystems[0]->global_pgid;
+	*p = first;
 }
 
-static void
-__ccw_device_verify_start(struct ccw_device *cdev)
+static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
 {
-	struct subchannel *sch;
-	__u8 func;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	/* Repeat for all paths. */
-	for (; cdev->private->imask; cdev->private->imask >>= 1,
-				     cdev->private->iretry = 5) {
-		if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
-			/* Path not available, try next. */
-			continue;
-		if (cdev->private->options.pgroup) {
-			if (sch->opm & cdev->private->imask)
-				func = SPID_FUNC_ESTABLISH;
-			else
-				func = SPID_FUNC_RESIGN;
-			ret = __ccw_device_do_pgid(cdev, func);
-		} else
-			ret = __ccw_device_do_nop(cdev);
-		/* We expect an interrupt in case of success or busy
-		 * indication. */
-		if (ret == 0 || ret == -EBUSY)
-			return;
-		/* Permanent path failure, try next. */
-	}
-	/* Done with all paths. */
-	ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -EACCES);
+	int i;
+
+	for (i = 0; i < 8; i++)
+		memcpy(&cdev->private->pgid[i], pgid, sizeof(struct pgid));
 }
-		
+
 /*
- * Got interrupt for Set Path Group ID.
+ * Process SENSE PGID data and report result.
  */
-void
-ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void snid_done(struct ccw_device *cdev, int rc)
 {
-	struct subchannel *sch;
-	struct irb *irb;
-	int ret;
-
-	irb = (struct irb *) __LC_IRB;
+	struct ccw_dev_id *id = &cdev->private->dev_id;
+	struct pgid *pgid;
+	int mismatch = 0;
+	int reserved = 0;
+	int reset = 0;
 
-	if (irb->scsw.cmd.stctl ==
-	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if (__ccw_device_should_retry(&irb->scsw))
-			__ccw_device_verify_start(cdev);
-		return;
+	if (rc)
+		goto out;
+	pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset);
+	if (!mismatch) {
+		pgid_fill(cdev, pgid);
+		cdev->private->flags.pgid_rdy = 1;
 	}
-	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
-		return;
-	sch = to_subchannel(cdev->dev.parent);
-	if (cdev->private->options.pgroup)
-		ret = __ccw_device_check_pgid(cdev);
-	else
-		ret = __ccw_device_check_nop(cdev);
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
+	if (reserved)
+		rc = -EUSERS;
+out:
+	CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x mism=%d "
+		      "rsvd=%d reset=%d\n", id->ssid, id->devno, rc,
+		      cdev->private->pgid_valid_mask, mismatch, reserved,
+		      reset);
+	ccw_device_sense_pgid_done(cdev, rc);
+}
 
-	switch (ret) {
-	/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
-	case 0:
-		/* Path verification ccw finished successfully, update lpm. */
-		sch->vpm |= sch->opm & cdev->private->imask;
-		/* Go on with next path. */
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-		__ccw_device_verify_start(cdev);
-		break;
-	case -EOPNOTSUPP:
-		/*
-		 * One of those strange devices which claim to be able
-		 * to do multipathing but not for Set Path Group ID.
-		 */
-		if (cdev->private->flags.pgid_single)
-			cdev->private->options.pgroup = 0;
-		else
-			cdev->private->flags.pgid_single = 1;
-		/* Retry */
-		sch->vpm = 0;
-		cdev->private->imask = 0x80;
-		cdev->private->iretry = 5;
-		/* fall through. */
-	case -EAGAIN:		/* Try again. */
-		__ccw_device_verify_start(cdev);
-		break;
-	case -ETIME:		/* Set path group id stopped by timeout. */
-		ccw_device_verify_done(cdev, -ETIME);
-		break;
-	case -EACCES:		/* channel is not operational. */
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-		__ccw_device_verify_start(cdev);
-		break;
-	}
+/*
+ * Create channel program to perform a SENSE PGID on a single path.
+ */
+static void snid_build_cp(struct ccw_device *cdev)
+{
+	struct ccw_request *req = &cdev->private->req;
+	struct ccw1 *cp = cdev->private->iccws;
+	int i = 8 - ffs(req->lpm);
+
+	/* Channel program setup. */
+	cp->cmd_code	= CCW_CMD_SENSE_PGID;
+	cp->cda		= (u32) (addr_t) &cdev->private->pgid[i];
+	cp->count	= sizeof(struct pgid);
+	cp->flags	= CCW_FLAG_SLI;
+	req->cp		= cp;
 }
 
-void
-ccw_device_verify_start(struct ccw_device *cdev)
+/*
+ * Perform SENSE PGID on a single path.
+ */
+static void snid_do(struct ccw_device *cdev)
 {
 	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
 
-	cdev->private->flags.pgid_single = 0;
-	cdev->private->imask = 0x80;
-	cdev->private->iretry = 5;
+	/* Adjust lpm if paths are not set in pam. */
+	req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam);
+	if (!req->lpm)
+		goto out_nopath;
+	snid_build_cp(cdev);
+	ccw_request_start(cdev);
+	return;
 
-	/* Start with empty vpm. */
-	sch->vpm = 0;
-
-	/* Get current pam. */
-	if (cio_update_schib(sch)) {
-		ccw_device_verify_done(cdev, -ENODEV);
-		return;
-	}
-	/* After 60s path verification is considered to have failed. */
-	ccw_device_set_timeout(cdev, 60*HZ);
-	__ccw_device_verify_start(cdev);
-}
-
-static void
-__ccw_device_disband_start(struct ccw_device *cdev)
-{
-	struct subchannel *sch;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	while (cdev->private->imask != 0) {
-		if (sch->lpm & cdev->private->imask) {
-			ret = __ccw_device_do_pgid(cdev, SPID_FUNC_DISBAND);
-			if (ret == 0)
-				return;
-		}
-		cdev->private->iretry = 5;
-		cdev->private->imask >>= 1;
-	}
-	ccw_device_disband_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);
+out_nopath:
+	snid_done(cdev, cdev->private->pgid_valid_mask ? 0 : -EACCES);
 }
 
 /*
- * Got interrupt for Unset Path Group ID.
+ * Process SENSE PGID request result for single path.
+ */
+static void snid_callback(struct ccw_device *cdev, void *data, int rc)
+{
+	struct ccw_request *req = &cdev->private->req;
+
+	if (rc == 0)
+		cdev->private->pgid_valid_mask |= req->lpm;
+	else if (rc != -EACCES)
+		goto err;
+	req->lpm >>= 1;
+	snid_do(cdev);
+	return;
+
+err:
+	snid_done(cdev, rc);
+}
+
+/**
+ * ccw_device_sense_pgid_start - perform SENSE PGID
+ * @cdev: ccw device
+ *
+ * Execute a SENSE PGID channel program on each path to @cdev to update its
+ * PGID information. When finished, call ccw_device_sense_id_done with a
+ * return code specifying the result.
  */
-void
-ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
+void ccw_device_sense_pgid_start(struct ccw_device *cdev)
 {
-	struct subchannel *sch;
-	struct irb *irb;
-	int ret;
+	struct ccw_request *req = &cdev->private->req;
 
-	irb = (struct irb *) __LC_IRB;
+	CIO_TRACE_EVENT(4, "snid");
+	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+	/* Initialize PGID data. */
+	memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
+	cdev->private->flags.pgid_rdy = 0;
+	cdev->private->pgid_valid_mask = 0;
+	/* Initialize request data. */
+	memset(req, 0, sizeof(*req));
+	req->timeout	= PGID_TIMEOUT;
+	req->maxretries	= PGID_RETRIES;
+	req->callback	= snid_callback;
+	req->lpm	= 0x80;
+	snid_do(cdev);
+}
 
-	if (irb->scsw.cmd.stctl ==
-	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if (__ccw_device_should_retry(&irb->scsw))
-			__ccw_device_disband_start(cdev);
-		return;
+/*
+ * Perform path verification.
+ */
+static void verify_start(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+
+	sch->vpm = 0;
+	/* Initialize request data. */
+	memset(req, 0, sizeof(*req));
+	req->timeout	= PGID_TIMEOUT;
+	req->maxretries	= PGID_RETRIES;
+	req->lpm	= 0x80;
+	if (cdev->private->options.pgroup) {
+		req->callback	= spid_callback;
+		spid_do(cdev);
+	} else {
+		req->filter	= nop_filter;
+		req->callback	= nop_callback;
+		nop_do(cdev);
 	}
-	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
-		return;
-	sch = to_subchannel(cdev->dev.parent);
-	ret = __ccw_device_check_pgid(cdev);
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-	switch (ret) {
-	/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
-	case 0:			/* disband successful. */
-		ccw_device_disband_done(cdev, ret);
-		break;
-	case -EOPNOTSUPP:
-		/*
-		 * One of those strange devices which claim to be able
-		 * to do multipathing but not for Unset Path Group ID.
-		 */
+}
+
+/**
+ * ccw_device_verify_start - perform path verification
+ * @cdev: ccw device
+ *
+ * Perform an I/O on each available channel path to @cdev to determine which
+ * paths are operational. The resulting path mask is stored in sch->vpm.
+ * If device options specify pathgrouping, establish a pathgroup for the
+ * operational paths. When finished, call ccw_device_verify_done with a
+ * return code specifying the result.
+ */
+void ccw_device_verify_start(struct ccw_device *cdev)
+{
+	CIO_TRACE_EVENT(4, "vrfy");
+	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+	if (!cdev->private->flags.pgid_rdy) {
+		/* No pathgrouping possible. */
+		cdev->private->options.pgroup = 0;
 		cdev->private->flags.pgid_single = 1;
-		/* fall through. */
-	case -EAGAIN:		/* Try again. */
-		__ccw_device_disband_start(cdev);
-		break;
-	case -ETIME:		/* Set path group id stopped by timeout. */
-		ccw_device_disband_done(cdev, -ETIME);
-		break;
-	case -EACCES:		/* channel is not operational. */
-		cdev->private->imask >>= 1;
-		cdev->private->iretry = 5;
-		__ccw_device_disband_start(cdev);
-		break;
-	}
+	} else
+		cdev->private->flags.pgid_single = 0;
+	cdev->private->flags.doverify = 0;
+	verify_start(cdev);
 }
 
-void
-ccw_device_disband_start(struct ccw_device *cdev)
+/*
+ * Process disband SET PGID request result.
+ */
+static void disband_callback(struct ccw_device *cdev, void *data, int rc)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_dev_id *id = &cdev->private->dev_id;
+
+	if (rc)
+		goto out;
+	/* Ensure consistent multipathing state at device and channel. */
+	cdev->private->flags.pgid_single = 1;
+	if (sch->config.mp) {
+		sch->config.mp = 0;
+		rc = cio_commit_config(sch);
+	}
+out:
+	CIO_MSG_EVENT(0, "disb: device 0.%x.%04x: rc=%d\n", id->ssid, id->devno,
+		      rc);
+	ccw_device_disband_done(cdev, rc);
+}
+
+/**
+ * ccw_device_disband_start - disband pathgroup
+ * @cdev: ccw device
+ *
+ * Execute a SET PGID channel program on @cdev to disband a previously
+ * established pathgroup. When finished, call ccw_device_disband_done with
+ * a return code specifying the result.
+ */
+void ccw_device_disband_start(struct ccw_device *cdev)
 {
-	/* After 60s disbanding is considered to have failed. */
-	ccw_device_set_timeout(cdev, 60*HZ);
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+	u8 fn;
 
-	cdev->private->flags.pgid_single = 0;
-	cdev->private->iretry = 5;
-	cdev->private->imask = 0x80;
-	__ccw_device_disband_start(cdev);
+	CIO_TRACE_EVENT(4, "disb");
+	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+	/* Request setup. */
+	memset(req, 0, sizeof(*req));
+	req->timeout	= PGID_TIMEOUT;
+	req->maxretries	= PGID_RETRIES;
+	req->lpm	= sch->schib.pmcw.pam & sch->opm;
+	req->callback	= disband_callback;
+	fn = SPID_FUNC_DISBAND;
+	if (!cdev->private->flags.pgid_single)
+		fn |= SPID_FUNC_MULTI_PATH;
+	spid_build_cp(cdev, fn);
+	ccw_request_start(cdev);
 }
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:20.000000000 +0100
@@ -149,8 +149,8 @@
 	struct ccw_dev_id dev_id;	/* device id */
 	struct subchannel_id schid;	/* subchannel number */
 	struct ccw_request req;		/* internal I/O request */
-	u8 imask;		/* lpm mask for SNID/SID/SPGID */
-	int iretry;		/* retry counter SNID/SID/SPGID */
+	int iretry;
+	u8 pgid_valid_mask;		/* mask of valid PGIDs */
 	struct {
 		unsigned int fast:1;	/* post with "channel end" */
 		unsigned int repall:1;	/* report every interrupt status */
@@ -167,6 +167,7 @@
 		unsigned int fake_irb:1;    /* deliver faked irb */
 		unsigned int intretry:1;    /* retry internal operation */
 		unsigned int resuming:1;    /* recognition while resume */
+		unsigned int pgid_rdy:1;    /* pgids are ready */
 	} __attribute__((packed)) flags;
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 39/52] [PATCH] cio: allow setting not-operational devices offline
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (37 preceding siblings ...)
  2009-11-13 15:09 ` [patch 38/52] [PATCH] cio: use ccw request infrastructure for pgid Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 40/52] [PATCH] cio: remove intretry flag Martin Schwidefsky
                   ` (13 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 138-cio-allow-offline.diff --]
[-- Type: text/plain, Size: 1286 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Accept a request for setting a not-operational device offline.
This way, users can remove devices from Linux which would otherwise
remain unusable until reboot.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |    9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:20.000000000 +0100
@@ -529,11 +529,10 @@
 	int force, ret;
 	unsigned long i;
 
-	if ((cdev->private->state != DEV_STATE_OFFLINE &&
-	     cdev->private->state != DEV_STATE_ONLINE &&
-	     cdev->private->state != DEV_STATE_BOXED &&
-	     cdev->private->state != DEV_STATE_DISCONNECTED) ||
-	    atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
+	if (!dev_fsm_final_state(cdev) &&
+	    cdev->private->state != DEV_STATE_DISCONNECTED)
+		return -EAGAIN;
+	if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
 		return -EAGAIN;
 
 	if (cdev->drv && !try_module_get(cdev->drv->owner)) {

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 40/52] [PATCH] cio: remove intretry flag
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (38 preceding siblings ...)
  2009-11-13 15:09 ` [patch 39/52] [PATCH] cio: allow setting not-operational devices offline Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 41/52] [PATCH] cio: split PGID settings and status Martin Schwidefsky
                   ` (12 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 139-cio-remove-intretry.diff --]
[-- Type: text/plain, Size: 7111 bytes --]

After changing all internal I/O functions to use the newly introduced
ccw request infrastructure, retries are handled automatically after a
clear operation. Therefore remove the internal retry flag and
associated code.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c        |   58 +++++++++++----------------------------
 drivers/s390/cio/device.h        |    1 
 drivers/s390/cio/device_fsm.c    |   27 ------------------
 drivers/s390/cio/device_ops.c    |    3 --
 drivers/s390/cio/device_status.c |    3 --
 drivers/s390/cio/io_sch.h        |    1 
 6 files changed, 18 insertions(+), 75 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:20.000000000 +0100
@@ -1068,36 +1068,6 @@
 		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 }
 
-static int check_for_io_on_path(struct subchannel *sch, int mask)
-{
-	if (cio_update_schib(sch))
-		return 0;
-	if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask)
-		return 1;
-	return 0;
-}
-
-static void terminate_internal_io(struct subchannel *sch,
-				  struct ccw_device *cdev)
-{
-	if (cio_clear(sch)) {
-		/* Recheck device in case clear failed. */
-		sch->lpm = 0;
-		if (cdev->online)
-			dev_fsm_event(cdev, DEV_EVENT_VERIFY);
-		else
-			css_schedule_eval(sch->schid);
-		return;
-	}
-	cdev->private->state = DEV_STATE_CLEAR_VERIFY;
-	/* Request retry of internal operation. */
-	cdev->private->flags.intretry = 1;
-	/* Call handler. */
-	if (cdev->handler)
-		cdev->handler(cdev, cdev->private->intparm,
-			      ERR_PTR(-EIO));
-}
-
 static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask)
 {
 	struct ccw_device *cdev;
@@ -1105,18 +1075,24 @@
 	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return;
-	if (check_for_io_on_path(sch, mask)) {
-		if (cdev->private->state == DEV_STATE_ONLINE)
-			ccw_device_kill_io(cdev);
-		else {
-			terminate_internal_io(sch, cdev);
-			/* Re-start path verification. */
-			dev_fsm_event(cdev, DEV_EVENT_VERIFY);
-		}
-	} else
-		/* trigger path verification. */
-		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+	if (cio_update_schib(sch))
+		goto err;
+	/* Check for I/O on path. */
+	if (scsw_actl(&sch->schib.scsw) == 0 || sch->schib.pmcw.lpum != mask)
+		goto out;
+	if (cdev->private->state == DEV_STATE_ONLINE) {
+		ccw_device_kill_io(cdev);
+		goto out;
+	}
+	if (cio_clear(sch))
+		goto err;
+out:
+	/* Trigger path verification. */
+	dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+	return;
 
+err:
+	dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 }
 
 static int io_subchannel_chp_event(struct subchannel *sch,
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:20.000000000 +0100
@@ -771,12 +771,6 @@
 	 */
 	if (scsw_fctl(&irb->scsw) &
 	    (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
-		/* Retry Basic Sense if requested. */
-		if (cdev->private->flags.intretry) {
-			cdev->private->flags.intretry = 0;
-			ccw_device_do_sense(cdev, irb);
-			return;
-		}
 		cdev->private->flags.dosense = 0;
 		memset(&cdev->private->irb, 0, sizeof(struct irb));
 		ccw_device_accumulate_irb(cdev, irb);
@@ -800,21 +794,6 @@
 }
 
 static void
-ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	struct irb *irb;
-
-	irb = (struct irb *) __LC_IRB;
-	/* Accumulate status. We don't do basic sense. */
-	ccw_device_accumulate_irb(cdev, irb);
-	/* Remember to clear irb to avoid residuals. */
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
-	/* Try to start delayed device verification. */
-	ccw_device_online_verify(cdev, 0);
-	/* Note: Don't call handler for cio initiated clear! */
-}
-
-static void
 ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
 {
 	struct subchannel *sch;
@@ -1069,12 +1048,6 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	/* states to wait for i/o completion before doing something */
-	[DEV_STATE_CLEAR_VERIFY] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
-		[DEV_EVENT_INTERRUPT]   = ccw_device_clear_verify,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
-		[DEV_EVENT_VERIFY]	= ccw_device_nop,
-	},
 	[DEV_STATE_TIMEOUT_KILL] = {
 		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_killing_irq,
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
@@ -21,7 +21,6 @@
 	DEV_STATE_DISBAND_PGID,
 	DEV_STATE_BOXED,
 	/* states to wait for i/o completion before doing something */
-	DEV_STATE_CLEAR_VERIFY,
 	DEV_STATE_TIMEOUT_KILL,
 	DEV_STATE_QUIESCE,
 	/* special states for devices gone not operational */
Index: quilt-2.6/drivers/s390/cio/device_ops.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_ops.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_ops.c	2009-11-13 16:08:20.000000000 +0100
@@ -167,8 +167,7 @@
 		return -EINVAL;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
-	if (cdev->private->state == DEV_STATE_VERIFY ||
-	    cdev->private->state == DEV_STATE_CLEAR_VERIFY) {
+	if (cdev->private->state == DEV_STATE_VERIFY) {
 		/* Remember to fake irb when finished. */
 		if (!cdev->private->flags.fake_irb) {
 			cdev->private->flags.fake_irb = 1;
Index: quilt-2.6/drivers/s390/cio/device_status.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_status.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_status.c	2009-11-13 16:08:20.000000000 +0100
@@ -336,9 +336,6 @@
 	sense_ccw->count = SENSE_MAX_COUNT;
 	sense_ccw->flags = CCW_FLAG_SLI;
 
-	/* Reset internal retry indication. */
-	cdev->private->flags.intretry = 0;
-
 	rc = cio_start(sch, sense_ccw, 0xff);
 	if (rc == -ENODEV || rc == -EACCES)
 		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:20.000000000 +0100
@@ -165,7 +165,6 @@
 		unsigned int donotify:1;    /* call notify function */
 		unsigned int recog_done:1;  /* dev. recog. complete */
 		unsigned int fake_irb:1;    /* deliver faked irb */
-		unsigned int intretry:1;    /* retry internal operation */
 		unsigned int resuming:1;    /* recognition while resume */
 		unsigned int pgid_rdy:1;    /* pgids are ready */
 	} __attribute__((packed)) flags;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 41/52] [PATCH] cio: split PGID settings and status
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (39 preceding siblings ...)
  2009-11-13 15:09 ` [patch 40/52] [PATCH] cio: remove intretry flag Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 42/52] [PATCH] cio: use sense-pgid operation for path verification Martin Schwidefsky
                   ` (11 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 140-cio-split-pgid.diff --]
[-- Type: text/plain, Size: 11071 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Split setting (driver wants feature enabled) and status (feature
setup was successful) for PGID related ccw device features so that
setup errors can be detected. Previously, incorrectly handled setup
errors could in rare cases lead to erratic I/O behavior and
permanently unusuable devices.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 arch/s390/include/asm/ccwdev.h |    4 ++++
 drivers/s390/block/dasd.c      |    7 -------
 drivers/s390/block/dasd_eckd.c |   12 +++++++++++-
 drivers/s390/char/tape_core.c  |    3 ++-
 drivers/s390/cio/device_fsm.c  |    2 +-
 drivers/s390/cio/device_ops.c  |   27 +++++++++++++++++++++++++++
 drivers/s390/cio/device_pgid.c |   33 ++++++++++++++++++++-------------
 drivers/s390/cio/io_sch.h      |    4 +++-
 8 files changed, 68 insertions(+), 24 deletions(-)

Index: quilt-2.6/arch/s390/include/asm/ccwdev.h
===================================================================
--- quilt-2.6.orig/arch/s390/include/asm/ccwdev.h	2009-11-13 15:48:32.000000000 +0100
+++ quilt-2.6/arch/s390/include/asm/ccwdev.h	2009-11-13 16:08:21.000000000 +0100
@@ -142,6 +142,8 @@
 extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long);
 extern int ccw_device_set_options(struct ccw_device *, unsigned long);
 extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
+int ccw_device_is_pathgroup(struct ccw_device *cdev);
+int ccw_device_is_multipath(struct ccw_device *cdev);
 
 /* Allow for i/o completion notification after primary interrupt status. */
 #define CCWDEV_EARLY_NOTIFICATION	0x0001
@@ -151,6 +153,8 @@
 #define CCWDEV_DO_PATHGROUP             0x0004
 /* Allow forced onlining of boxed devices. */
 #define CCWDEV_ALLOW_FORCE              0x0008
+/* Try to use multipath mode. */
+#define CCWDEV_DO_MULTIPATH		0x0010
 
 extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
 			    unsigned long, __u8, unsigned long);
Index: quilt-2.6/drivers/s390/block/dasd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd.c	2009-11-13 16:08:17.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd.c	2009-11-13 16:08:21.000000000 +0100
@@ -2301,13 +2301,6 @@
 {
 	int ret;
 
-	ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
-	if (ret) {
-		DBF_EVENT(DBF_WARNING,
-		       "dasd_generic_probe: could not set ccw-device options "
-		       "for %s\n", dev_name(&cdev->dev));
-		return ret;
-	}
 	ret = dasd_add_sysfs_files(cdev);
 	if (ret) {
 		DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s",
Index: quilt-2.6/drivers/s390/block/dasd_eckd.c
===================================================================
--- quilt-2.6.orig/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:17.000000000 +0100
+++ quilt-2.6/drivers/s390/block/dasd_eckd.c	2009-11-13 16:08:21.000000000 +0100
@@ -90,7 +90,8 @@
 	int ret;
 
 	/* set ECKD specific ccw-device options */
-	ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+	ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE |
+				     CCWDEV_DO_PATHGROUP | CCWDEV_DO_MULTIPATH);
 	if (ret) {
 		DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s",
 				"dasd_eckd_probe: could not set "
@@ -1090,6 +1091,15 @@
 	struct dasd_block *block;
 	int is_known, rc;
 
+	if (!ccw_device_is_pathgroup(device->cdev)) {
+		dev_warn(&device->cdev->dev,
+			 "A channel path group could not be established\n");
+		return -EIO;
+	}
+	if (!ccw_device_is_multipath(device->cdev)) {
+		dev_info(&device->cdev->dev,
+			 "The DASD is not operating in multipath mode\n");
+	}
 	private = (struct dasd_eckd_private *) device->private;
 	if (!private) {
 		private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
Index: quilt-2.6/drivers/s390/char/tape_core.c
===================================================================
--- quilt-2.6.orig/drivers/s390/char/tape_core.c	2009-11-13 15:48:33.000000000 +0100
+++ quilt-2.6/drivers/s390/char/tape_core.c	2009-11-13 16:08:21.000000000 +0100
@@ -579,7 +579,8 @@
 	device = tape_alloc_device();
 	if (IS_ERR(device))
 		return -ENODEV;
-	ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+	ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP |
+				     CCWDEV_DO_MULTIPATH);
 	ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
 	if (ret) {
 		tape_put_device(device);
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:21.000000000 +0100
@@ -601,7 +601,7 @@
 	if (cdev->private->state != DEV_STATE_ONLINE)
 		return -EINVAL;
 	/* Are we doing path grouping? */
-	if (!cdev->private->options.pgroup) {
+	if (!cdev->private->flags.pgroup) {
 		/* No, set state offline immediately. */
 		ccw_device_done(cdev, DEV_STATE_OFFLINE);
 		return 0;
Index: quilt-2.6/drivers/s390/cio/device_ops.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_ops.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_ops.c	2009-11-13 16:08:21.000000000 +0100
@@ -46,6 +46,7 @@
 	cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0;
 	cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0;
 	cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0;
+	cdev->private->options.mpath = (flags & CCWDEV_DO_MULTIPATH) != 0;
 	return 0;
 }
 
@@ -74,6 +75,7 @@
 	cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0;
 	cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0;
 	cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0;
+	cdev->private->options.mpath |= (flags & CCWDEV_DO_MULTIPATH) != 0;
 	return 0;
 }
 
@@ -90,9 +92,34 @@
 	cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0;
 	cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0;
 	cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
+	cdev->private->options.mpath &= (flags & CCWDEV_DO_MULTIPATH) == 0;
 }
 
 /**
+ * ccw_device_is_pathgroup - determine if paths to this device are grouped
+ * @cdev: ccw device
+ *
+ * Return non-zero if there is a path group, zero otherwise.
+ */
+int ccw_device_is_pathgroup(struct ccw_device *cdev)
+{
+	return cdev->private->flags.pgroup;
+}
+EXPORT_SYMBOL(ccw_device_is_pathgroup);
+
+/**
+ * ccw_device_is_multipath - determine if device is operating in multipath mode
+ * @cdev: ccw device
+ *
+ * Return non-zero if device is operating in multipath mode, zero otherwise.
+ */
+int ccw_device_is_multipath(struct ccw_device *cdev)
+{
+	return cdev->private->flags.mpath;
+}
+EXPORT_SYMBOL(ccw_device_is_multipath);
+
+/**
  * ccw_device_clear() - terminate I/O request processing
  * @cdev: target ccw device
  * @intparm: interruption parameter; value is only used if no I/O is
Index: quilt-2.6/drivers/s390/cio/device_pgid.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:21.000000000 +0100
@@ -30,8 +30,8 @@
 {
 	struct subchannel *sch = to_subchannel(cdev->dev.parent);
 	struct ccw_dev_id *id = &cdev->private->dev_id;
-	int mpath = !cdev->private->flags.pgid_single;
-	int pgroup = cdev->private->options.pgroup;
+	int mpath = cdev->private->flags.mpath;
+	int pgroup = cdev->private->flags.pgroup;
 
 	if (rc)
 		goto out;
@@ -150,7 +150,7 @@
 		fn = SPID_FUNC_ESTABLISH;
 	else
 		fn = SPID_FUNC_RESIGN;
-	if (!cdev->private->flags.pgid_single)
+	if (cdev->private->flags.mpath)
 		fn |= SPID_FUNC_MULTI_PATH;
 	spid_build_cp(cdev, fn);
 	ccw_request_start(cdev);
@@ -177,13 +177,13 @@
 	case -EACCES:
 		break;
 	case -EOPNOTSUPP:
-		if (!cdev->private->flags.pgid_single) {
+		if (cdev->private->flags.mpath) {
 			/* Try without multipathing. */
-			cdev->private->flags.pgid_single = 1;
+			cdev->private->flags.mpath = 0;
 			goto out_restart;
 		}
 		/* Try without pathgrouping. */
-		cdev->private->options.pgroup = 0;
+		cdev->private->flags.pgroup = 0;
 		goto out_restart;
 	default:
 		goto err;
@@ -374,7 +374,7 @@
 	req->timeout	= PGID_TIMEOUT;
 	req->maxretries	= PGID_RETRIES;
 	req->lpm	= 0x80;
-	if (cdev->private->options.pgroup) {
+	if (cdev->private->flags.pgroup) {
 		req->callback	= spid_callback;
 		spid_do(cdev);
 	} else {
@@ -400,10 +400,17 @@
 	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
 	if (!cdev->private->flags.pgid_rdy) {
 		/* No pathgrouping possible. */
-		cdev->private->options.pgroup = 0;
-		cdev->private->flags.pgid_single = 1;
-	} else
-		cdev->private->flags.pgid_single = 0;
+		cdev->private->flags.pgroup = 0;
+		cdev->private->flags.mpath = 0;
+	} else {
+		/*
+		 * Initialize pathgroup and multipath state with target values.
+		 * They may change in the course of path verification.
+		 */
+		cdev->private->flags.pgroup = cdev->private->options.pgroup;
+		cdev->private->flags.mpath = cdev->private->options.mpath;
+
+	}
 	cdev->private->flags.doverify = 0;
 	verify_start(cdev);
 }
@@ -419,7 +426,7 @@
 	if (rc)
 		goto out;
 	/* Ensure consistent multipathing state at device and channel. */
-	cdev->private->flags.pgid_single = 1;
+	cdev->private->flags.mpath = 0;
 	if (sch->config.mp) {
 		sch->config.mp = 0;
 		rc = cio_commit_config(sch);
@@ -453,7 +460,7 @@
 	req->lpm	= sch->schib.pmcw.pam & sch->opm;
 	req->callback	= disband_callback;
 	fn = SPID_FUNC_DISBAND;
-	if (!cdev->private->flags.pgid_single)
+	if (cdev->private->flags.mpath)
 		fn |= SPID_FUNC_MULTI_PATH;
 	spid_build_cp(cdev, fn);
 	ccw_request_start(cdev);
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:21.000000000 +0100
@@ -156,9 +156,9 @@
 		unsigned int repall:1;	/* report every interrupt status */
 		unsigned int pgroup:1;	/* do path grouping */
 		unsigned int force:1;	/* allow forced online */
+		unsigned int mpath:1;	/* do multipathing */
 	} __attribute__ ((packed)) options;
 	struct {
-		unsigned int pgid_single:1; /* use single path for Set PGID */
 		unsigned int esid:1;	    /* Ext. SenseID supported by HW */
 		unsigned int dosense:1;	    /* delayed SENSE required */
 		unsigned int doverify:1;    /* delayed path verification */
@@ -167,6 +167,8 @@
 		unsigned int fake_irb:1;    /* deliver faked irb */
 		unsigned int resuming:1;    /* recognition while resume */
 		unsigned int pgid_rdy:1;    /* pgids are ready */
+		unsigned int pgroup:1;	    /* pathgroup is set up */
+		unsigned int mpath:1;	    /* multipathing is set up */
 	} __attribute__((packed)) flags;
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 42/52] [PATCH] cio: use sense-pgid operation for path verification
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (40 preceding siblings ...)
  2009-11-13 15:09 ` [patch 41/52] [PATCH] cio: split PGID settings and status Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 43/52] [PATCH] cio: make steal lock procedure more robust Martin Schwidefsky
                   ` (10 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 141-cio-path-verification.diff --]
[-- Type: text/plain, Size: 10199 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Set-pgid operations fail for some device types under z/VM for which
the hypervisor has already set the pgid. Also reserved devices or
changed pgids are not correctly recognized. Fix these problems by
using a combination of sense-pgid and set-pgid and by also accepting
pre-defined pgid settings.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.h      |    3 
 drivers/s390/cio/device_fsm.c  |   41 +----------
 drivers/s390/cio/device_pgid.c |  148 ++++++++++++++++++++++++++---------------
 drivers/s390/cio/io_sch.h      |    1 
 4 files changed, 99 insertions(+), 94 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:21.000000000 +0100
@@ -395,33 +395,6 @@
 }
 
 /*
- * Function called from device_pgid.c after sense path ground has completed.
- */
-void
-ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
-{
-	struct subchannel *sch;
-
-	sch = to_subchannel(cdev->dev.parent);
-	switch (err) {
-	case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
-	case 0: /* success */
-	case -EACCES: /* partial success, some paths not operational */
-		break;
-	case -ETIME:		/* Sense path group id stopped by timeout. */
-	case -EUSERS:		/* device is reserved for someone else. */
-		ccw_device_done(cdev, DEV_STATE_BOXED);
-		return;
-	default:
-		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
-		return;
-	}
-	/* Start Path Group verification. */
-	cdev->private->state = DEV_STATE_VERIFY;
-	ccw_device_verify_start(cdev);
-}
-
-/*
  * Start device recognition.
  */
 void ccw_device_recognition(struct ccw_device *cdev)
@@ -503,6 +476,7 @@
 		}
 		break;
 	case -ETIME:
+	case -EUSERS:
 		/* Reset oper notify indication after verify error. */
 		cdev->private->flags.donotify = 0;
 		ccw_device_done(cdev, DEV_STATE_BOXED);
@@ -540,16 +514,9 @@
 			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 		return ret;
 	}
-	/* Do we want to do path grouping? */
-	if (!cdev->private->options.pgroup) {
-		/* Start initial path verification. */
-		cdev->private->state = DEV_STATE_VERIFY;
-		ccw_device_verify_start(cdev);
-		return 0;
-	}
-	/* Do a SensePGID first. */
-	cdev->private->state = DEV_STATE_SENSE_PGID;
-	ccw_device_sense_pgid_start(cdev);
+	/* Start initial path verification. */
+	cdev->private->state = DEV_STATE_VERIFY;
+	ccw_device_verify_start(cdev);
 	return 0;
 }
 
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:21.000000000 +0100
@@ -110,9 +110,6 @@
 void ccw_device_sense_id_done(struct ccw_device *, int);
 
 /* Function prototypes for path grouping stuff. */
-void ccw_device_sense_pgid_start(struct ccw_device *);
-void ccw_device_sense_pgid_done(struct ccw_device *, int);
-
 void ccw_device_verify_start(struct ccw_device *);
 void ccw_device_verify_done(struct ccw_device *, int);
 
Index: quilt-2.6/drivers/s390/cio/device_pgid.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:21.000000000 +0100
@@ -141,8 +141,8 @@
 	struct ccw_request *req = &cdev->private->req;
 	u8 fn;
 
-	/* Adjust lpm if paths are not set in pam. */
-	req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam);
+	/* Use next available path that is not already in correct state. */
+	req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & ~sch->vpm);
 	if (!req->lpm)
 		goto out_nopath;
 	/* Channel program setup. */
@@ -199,6 +199,19 @@
 	verify_done(cdev, rc);
 }
 
+static void spid_start(struct ccw_device *cdev)
+{
+	struct ccw_request *req = &cdev->private->req;
+
+	/* Initialize request data. */
+	memset(req, 0, sizeof(*req));
+	req->timeout	= PGID_TIMEOUT;
+	req->maxretries	= PGID_RETRIES;
+	req->lpm	= 0x80;
+	req->callback	= spid_callback;
+	spid_do(cdev);
+}
+
 static int pgid_cmp(struct pgid *p1, struct pgid *p2)
 {
 	return memcmp((char *) p1 + 1, (char *) p2 + 1,
@@ -241,6 +254,40 @@
 	*p = first;
 }
 
+static u8 pgid_to_vpm(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct pgid *pgid;
+	int i;
+	int lpm;
+	u8 vpm = 0;
+
+	/* Set VPM bits for paths which are already in the target state. */
+	for (i = 0; i < 8; i++) {
+		lpm = 0x80 >> i;
+		if ((cdev->private->pgid_valid_mask & lpm) == 0)
+			continue;
+		pgid = &cdev->private->pgid[i];
+		if (sch->opm & lpm) {
+			if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED)
+				continue;
+		} else {
+			if (pgid->inf.ps.state1 != SNID_STATE1_UNGROUPED)
+				continue;
+		}
+		if (cdev->private->flags.mpath) {
+			if (pgid->inf.ps.state3 != SNID_STATE3_MULTI_PATH)
+				continue;
+		} else {
+			if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH)
+				continue;
+		}
+		vpm |= lpm;
+	}
+
+	return vpm;
+}
+
 static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
 {
 	int i;
@@ -255,6 +302,7 @@
 static void snid_done(struct ccw_device *cdev, int rc)
 {
 	struct ccw_dev_id *id = &cdev->private->dev_id;
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
 	struct pgid *pgid;
 	int mismatch = 0;
 	int reserved = 0;
@@ -263,18 +311,38 @@
 	if (rc)
 		goto out;
 	pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset);
-	if (!mismatch) {
-		pgid_fill(cdev, pgid);
-		cdev->private->flags.pgid_rdy = 1;
-	}
 	if (reserved)
 		rc = -EUSERS;
+	else if (mismatch)
+		rc = -EOPNOTSUPP;
+	else {
+		sch->vpm = pgid_to_vpm(cdev);
+		pgid_fill(cdev, pgid);
+	}
 out:
-	CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x mism=%d "
-		      "rsvd=%d reset=%d\n", id->ssid, id->devno, rc,
-		      cdev->private->pgid_valid_mask, mismatch, reserved,
-		      reset);
-	ccw_device_sense_pgid_done(cdev, rc);
+	CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
+		      "mism=%d rsvd=%d reset=%d\n", id->ssid, id->devno, rc,
+		      cdev->private->pgid_valid_mask, sch->vpm, mismatch,
+		      reserved, reset);
+	switch (rc) {
+	case 0:
+		/* Anything left to do? */
+		if (sch->vpm == sch->schib.pmcw.pam) {
+			verify_done(cdev, sch->vpm == 0 ? -EACCES : 0);
+			return;
+		}
+		/* Perform path-grouping. */
+		spid_start(cdev);
+		break;
+	case -EOPNOTSUPP:
+		/* Path-grouping not supported. */
+		cdev->private->flags.pgroup = 0;
+		cdev->private->flags.mpath = 0;
+		verify_start(cdev);
+		break;
+	default:
+		verify_done(cdev, rc);
+	}
 }
 
 /*
@@ -333,33 +401,6 @@
 	snid_done(cdev, rc);
 }
 
-/**
- * ccw_device_sense_pgid_start - perform SENSE PGID
- * @cdev: ccw device
- *
- * Execute a SENSE PGID channel program on each path to @cdev to update its
- * PGID information. When finished, call ccw_device_sense_id_done with a
- * return code specifying the result.
- */
-void ccw_device_sense_pgid_start(struct ccw_device *cdev)
-{
-	struct ccw_request *req = &cdev->private->req;
-
-	CIO_TRACE_EVENT(4, "snid");
-	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
-	/* Initialize PGID data. */
-	memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
-	cdev->private->flags.pgid_rdy = 0;
-	cdev->private->pgid_valid_mask = 0;
-	/* Initialize request data. */
-	memset(req, 0, sizeof(*req));
-	req->timeout	= PGID_TIMEOUT;
-	req->maxretries	= PGID_RETRIES;
-	req->callback	= snid_callback;
-	req->lpm	= 0x80;
-	snid_do(cdev);
-}
-
 /*
  * Perform path verification.
  */
@@ -367,6 +408,7 @@
 {
 	struct subchannel *sch = to_subchannel(cdev->dev.parent);
 	struct ccw_request *req = &cdev->private->req;
+	struct ccw_dev_id *devid = &cdev->private->dev_id;
 
 	sch->vpm = 0;
 	/* Initialize request data. */
@@ -375,9 +417,13 @@
 	req->maxretries	= PGID_RETRIES;
 	req->lpm	= 0x80;
 	if (cdev->private->flags.pgroup) {
-		req->callback	= spid_callback;
-		spid_do(cdev);
+		CIO_TRACE_EVENT(4, "snid");
+		CIO_HEX_EVENT(4, devid, sizeof(*devid));
+		req->callback	= snid_callback;
+		snid_do(cdev);
 	} else {
+		CIO_TRACE_EVENT(4, "nop");
+		CIO_HEX_EVENT(4, devid, sizeof(*devid));
 		req->filter	= nop_filter;
 		req->callback	= nop_callback;
 		nop_do(cdev);
@@ -398,19 +444,15 @@
 {
 	CIO_TRACE_EVENT(4, "vrfy");
 	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
-	if (!cdev->private->flags.pgid_rdy) {
-		/* No pathgrouping possible. */
-		cdev->private->flags.pgroup = 0;
-		cdev->private->flags.mpath = 0;
-	} else {
-		/*
-		 * Initialize pathgroup and multipath state with target values.
-		 * They may change in the course of path verification.
-		 */
-		cdev->private->flags.pgroup = cdev->private->options.pgroup;
-		cdev->private->flags.mpath = cdev->private->options.mpath;
-
-	}
+	/* Initialize PGID data. */
+	memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
+	cdev->private->pgid_valid_mask = 0;
+	/*
+	 * Initialize pathgroup and multipath state with target values.
+	 * They may change in the course of path verification.
+	 */
+	cdev->private->flags.pgroup = cdev->private->options.pgroup;
+	cdev->private->flags.mpath = cdev->private->options.mpath;
 	cdev->private->flags.doverify = 0;
 	verify_start(cdev);
 }
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:21.000000000 +0100
@@ -166,7 +166,6 @@
 		unsigned int recog_done:1;  /* dev. recog. complete */
 		unsigned int fake_irb:1;    /* deliver faked irb */
 		unsigned int resuming:1;    /* recognition while resume */
-		unsigned int pgid_rdy:1;    /* pgids are ready */
 		unsigned int pgroup:1;	    /* pathgroup is set up */
 		unsigned int mpath:1;	    /* multipathing is set up */
 	} __attribute__((packed)) flags;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 43/52] [PATCH] cio: make steal lock procedure more robust
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (41 preceding siblings ...)
  2009-11-13 15:09 ` [patch 42/52] [PATCH] cio: use sense-pgid operation for path verification Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 44/52] [PATCH] cio: remove registered flag from ccw_device_private Martin Schwidefsky
                   ` (9 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 142-cio-steal-lock.diff --]
[-- Type: text/plain, Size: 9953 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

An Unconditional Reserve + Release operation (steal lock) for a
boxed device may fail when encountering special error cases
(e.g. unit checks or path errors). Fix this by using the more
robust ccw_request infrastructure for performing the steal lock
CCW program.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.h      |    4 +
 drivers/s390/cio/device_fsm.c  |   55 +++++++++-----------
 drivers/s390/cio/device_ops.c  |  112 +++++++++++++++++++----------------------
 drivers/s390/cio/device_pgid.c |   52 +++++++++++++++++++
 4 files changed, 134 insertions(+), 89 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:21.000000000 +0100
@@ -641,6 +641,23 @@
 }
 
 /*
+ * Handle path verification event in boxed state.
+ */
+static void ccw_device_boxed_verify(struct ccw_device *cdev,
+				    enum dev_event dev_event)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+	if (cdev->online) {
+		if (cio_enable_subchannel(sch, (u32) (addr_t) sch))
+			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+		else
+			ccw_device_online_verify(cdev, dev_event);
+	} else
+		css_schedule_eval(sch->schid);
+}
+
+/*
  * Got an interrupt for a normal io (state online).
  */
 static void
@@ -817,32 +834,6 @@
 }
 
 static void
-ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	struct irb *irb;
-
-	switch (dev_event) {
-	case DEV_EVENT_INTERRUPT:
-		irb = (struct irb *) __LC_IRB;
-		/* Check for unsolicited interrupt. */
-		if ((scsw_stctl(&irb->scsw) ==
-		     (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
-		    (!scsw_cc(&irb->scsw)))
-			/* FIXME: we should restart stlck here, but this
-			 * is extremely unlikely ... */
-			goto out_wakeup;
-
-		ccw_device_accumulate_irb(cdev, irb);
-		/* We don't care about basic sense etc. */
-		break;
-	default: /* timeout */
-		break;
-	}
-out_wakeup:
-	wake_up(&cdev->private->wait_q);
-}
-
-static void
 ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
 {
 	struct subchannel *sch;
@@ -1010,9 +1001,9 @@
 	},
 	[DEV_STATE_BOXED] = {
 		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
-		[DEV_EVENT_INTERRUPT]	= ccw_device_stlck_done,
-		[DEV_EVENT_TIMEOUT]	= ccw_device_stlck_done,
-		[DEV_EVENT_VERIFY]	= ccw_device_nop,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_nop,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
+		[DEV_EVENT_VERIFY]	= ccw_device_boxed_verify,
 	},
 	/* states to wait for i/o completion before doing something */
 	[DEV_STATE_TIMEOUT_KILL] = {
@@ -1052,6 +1043,12 @@
 		[DEV_EVENT_TIMEOUT]	= ccw_device_update_cmfblock,
 		[DEV_EVENT_VERIFY]	= ccw_device_update_cmfblock,
 	},
+	[DEV_STATE_STEAL_LOCK] = {
+		[DEV_EVENT_NOTOPER]	= ccw_device_request_event,
+		[DEV_EVENT_INTERRUPT]	= ccw_device_request_event,
+		[DEV_EVENT_TIMEOUT]	= ccw_device_request_event,
+		[DEV_EVENT_VERIFY]	= ccw_device_nop,
+	},
 };
 
 EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
Index: quilt-2.6/drivers/s390/cio/device.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.h	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.h	2009-11-13 16:08:21.000000000 +0100
@@ -28,6 +28,7 @@
 	DEV_STATE_DISCONNECTED_SENSE_ID,
 	DEV_STATE_CMFCHANGE,
 	DEV_STATE_CMFUPDATE,
+	DEV_STATE_STEAL_LOCK,
 	/* last element! */
 	NR_DEV_STATES
 };
@@ -116,6 +117,9 @@
 void ccw_device_disband_start(struct ccw_device *);
 void ccw_device_disband_done(struct ccw_device *, int);
 
+void ccw_device_stlck_start(struct ccw_device *, void *, void *, void *);
+void ccw_device_stlck_done(struct ccw_device *, void *, int);
+
 int ccw_device_call_handler(struct ccw_device *);
 
 int ccw_device_stlck(struct ccw_device *);
Index: quilt-2.6/drivers/s390/cio/device_ops.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_ops.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_ops.c	2009-11-13 16:08:21.000000000 +0100
@@ -11,6 +11,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/completion.h>
 
 #include <asm/ccwdev.h>
 #include <asm/idals.h>
@@ -504,74 +505,65 @@
 	return sch->lpm;
 }
 
-/*
- * Try to break the lock on a boxed device.
- */
-int
-ccw_device_stlck(struct ccw_device *cdev)
-{
-	void *buf, *buf2;
-	unsigned long flags;
-	struct subchannel *sch;
-	int ret;
+struct stlck_data {
+	struct completion done;
+	int rc;
+};
 
-	if (!cdev)
-		return -ENODEV;
+void ccw_device_stlck_done(struct ccw_device *cdev, void *data, int rc)
+{
+	struct stlck_data *sdata = data;
 
-	if (cdev->drv && !cdev->private->options.force)
-		return -EINVAL;
+	sdata->rc = rc;
+	complete(&sdata->done);
+}
 
-	sch = to_subchannel(cdev->dev.parent);
-	
-	CIO_TRACE_EVENT(2, "stl lock");
-	CIO_TRACE_EVENT(2, dev_name(&cdev->dev));
+/*
+ * Perform unconditional reserve + release.
+ */
+int ccw_device_stlck(struct ccw_device *cdev)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct stlck_data data;
+	u8 *buffer;
+	int rc;
 
-	buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-	buf2 = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
-	if (!buf2) {
-		kfree(buf);
-		return -ENOMEM;
+	/* Check if steal lock operation is valid for this device. */
+	if (cdev->drv) {
+		if (!cdev->private->options.force)
+			return -EINVAL;
 	}
-	spin_lock_irqsave(sch->lock, flags);
-	ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
-	if (ret)
-		goto out_unlock;
-	/*
-	 * Setup ccw. We chain an unconditional reserve and a release so we
-	 * only break the lock.
-	 */
-	cdev->private->iccws[0].cmd_code = CCW_CMD_STLCK;
-	cdev->private->iccws[0].cda = (__u32) __pa(buf);
-	cdev->private->iccws[0].count = 32;
-	cdev->private->iccws[0].flags = CCW_FLAG_CC;
-	cdev->private->iccws[1].cmd_code = CCW_CMD_RELEASE;
-	cdev->private->iccws[1].cda = (__u32) __pa(buf2);
-	cdev->private->iccws[1].count = 32;
-	cdev->private->iccws[1].flags = 0;
-	ret = cio_start(sch, cdev->private->iccws, 0);
-	if (ret) {
-		cio_disable_subchannel(sch); //FIXME: return code?
+	buffer = kzalloc(64, GFP_DMA | GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	init_completion(&data.done);
+	data.rc = -EIO;
+	spin_lock_irq(sch->lock);
+	rc = cio_enable_subchannel(sch, (u32) (addr_t) sch);
+	if (rc)
 		goto out_unlock;
+	/* Perform operation. */
+	cdev->private->state = DEV_STATE_STEAL_LOCK,
+	ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]);
+	spin_unlock_irq(sch->lock);
+	/* Wait for operation to finish. */
+	if (wait_for_completion_interruptible(&data.done)) {
+		/* Got a signal. */
+		spin_lock_irq(sch->lock);
+		ccw_request_cancel(cdev);
+		spin_unlock_irq(sch->lock);
+		wait_for_completion(&data.done);
 	}
-	cdev->private->irb.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
-	spin_unlock_irqrestore(sch->lock, flags);
-	wait_event(cdev->private->wait_q,
-		   cdev->private->irb.scsw.cmd.actl == 0);
-	spin_lock_irqsave(sch->lock, flags);
-	cio_disable_subchannel(sch); //FIXME: return code?
-	if ((cdev->private->irb.scsw.cmd.dstat !=
-	     (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-	    (cdev->private->irb.scsw.cmd.cstat != 0))
-		ret = -EIO;
-	/* Clear irb. */
-	memset(&cdev->private->irb, 0, sizeof(struct irb));
+	rc = data.rc;
+	/* Check results. */
+	spin_lock_irq(sch->lock);
+	cio_disable_subchannel(sch);
+	cdev->private->state = DEV_STATE_BOXED;
 out_unlock:
-	kfree(buf);
-	kfree(buf2);
-	spin_unlock_irqrestore(sch->lock, flags);
-	return ret;
+	spin_unlock_irq(sch->lock);
+	kfree(buffer);
+
+	return rc;
 }
 
 void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
Index: quilt-2.6/drivers/s390/cio/device_pgid.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:21.000000000 +0100
@@ -507,3 +507,55 @@
 	spid_build_cp(cdev, fn);
 	ccw_request_start(cdev);
 }
+
+static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
+{
+	struct ccw_request *req = &cdev->private->req;
+	struct ccw1 *cp = cdev->private->iccws;
+
+	cp[0].cmd_code = CCW_CMD_STLCK;
+	cp[0].cda = (u32) (addr_t) buf1;
+	cp[0].count = 32;
+	cp[0].flags = CCW_FLAG_CC;
+	cp[1].cmd_code = CCW_CMD_RELEASE;
+	cp[1].cda = (u32) (addr_t) buf2;
+	cp[1].count = 32;
+	cp[1].flags = 0;
+	req->cp = cp;
+}
+
+static void stlck_callback(struct ccw_device *cdev, void *data, int rc)
+{
+	ccw_device_stlck_done(cdev, data, rc);
+}
+
+/**
+ * ccw_device_stlck_start - perform unconditional release
+ * @cdev: ccw device
+ * @data: data pointer to be passed to ccw_device_stlck_done
+ * @buf1: data pointer used in channel program
+ * @buf2: data pointer used in channel program
+ *
+ * Execute a channel program on @cdev to release an existing PGID reservation.
+ * When finished, call ccw_device_stlck_done with a return code specifying the
+ * result.
+ */
+void ccw_device_stlck_start(struct ccw_device *cdev, void *data, void *buf1,
+			    void *buf2)
+{
+	struct subchannel *sch = to_subchannel(cdev->dev.parent);
+	struct ccw_request *req = &cdev->private->req;
+
+	CIO_TRACE_EVENT(4, "stlck");
+	CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+	/* Request setup. */
+	memset(req, 0, sizeof(*req));
+	req->timeout	= PGID_TIMEOUT;
+	req->maxretries	= PGID_RETRIES;
+	req->lpm	= sch->schib.pmcw.pam & sch->opm;
+	req->data	= data;
+	req->callback	= stlck_callback;
+	stlck_build_cp(cdev, buf1, buf2);
+	ccw_request_start(cdev);
+}
+

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 44/52] [PATCH] cio: remove registered flag from ccw_device_private
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (42 preceding siblings ...)
  2009-11-13 15:09 ` [patch 43/52] [PATCH] cio: make steal lock procedure more robust Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 45/52] [PATCH] cio: add per device initialization status flag Martin Schwidefsky
                   ` (8 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 143-cio-rm-registered-flag.diff --]
[-- Type: text/plain, Size: 2361 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

We used to maintain a "registered" flag in our ccw_device_private
structure. This patch removes the "registered" flag and converts
all users of it to device_is_registered which has the exact same
meaning.

Note: The usage the atomic operation test_and_clear_bit is replaced
by the non-atomic if (device_is_registered()) device_del(). This
will not do harm, since we serialize calls to ccw_device_unregister
with a single-threaded workqueue.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |   11 +++--------
 drivers/s390/cio/io_sch.h |    1 -
 2 files changed, 3 insertions(+), 9 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:21.000000000 +0100
@@ -303,7 +303,7 @@
 
 static void ccw_device_unregister(struct ccw_device *cdev)
 {
-	if (test_and_clear_bit(1, &cdev->private->registered)) {
+	if (device_is_registered(&cdev->dev)) {
 		device_del(&cdev->dev);
 		/* Release reference from device_initialize(). */
 		put_device(&cdev->dev);
@@ -640,12 +640,7 @@
 			   cdev->private->dev_id.devno);
 	if (ret)
 		return ret;
-	ret = device_add(dev);
-	if (ret)
-		return ret;
-
-	set_bit(1, &cdev->private->registered);
-	return ret;
+	return device_add(dev);
 }
 
 static int match_dev_id(struct device *dev, void *data)
@@ -669,7 +664,7 @@
 {
 	int ret;
 
-	if (test_bit(1, &cdev->private->registered)) {
+	if (device_is_registered(&cdev->dev)) {
 		device_release_driver(&cdev->dev);
 		ret = device_attach(&cdev->dev);
 		WARN_ON(ret == -ENODEV);
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:21.000000000 +0100
@@ -145,7 +145,6 @@
 	struct subchannel *sch;
 	int state;		/* device state */
 	atomic_t onoff;
-	unsigned long registered;
 	struct ccw_dev_id dev_id;	/* device id */
 	struct subchannel_id schid;	/* subchannel number */
 	struct ccw_request req;		/* internal I/O request */

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 45/52] [PATCH] cio: add per device initialization status flag
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (43 preceding siblings ...)
  2009-11-13 15:09 ` [patch 44/52] [PATCH] cio: remove registered flag from ccw_device_private Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 46/52] [PATCH] cio: fix quiesce state Martin Schwidefsky
                   ` (7 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 144-cio-device-init-flag.diff --]
[-- Type: text/plain, Size: 2324 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

The function ccw_device_unregister has to ensure to remove
all references obtained by device_add and device_initialize.
Unfortunately it gets called for devices which are
1) uninitialized, 2) initialized but unregistered, and
3) registered devices. To distinguish 1) and 2) this patch
introduces a new flag "initialized", which is 1 as long as we
hold the initial device reference.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |    6 ++++++
 drivers/s390/cio/io_sch.h |    1 +
 2 files changed, 7 insertions(+)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
@@ -304,7 +304,11 @@
 static void ccw_device_unregister(struct ccw_device *cdev)
 {
 	if (device_is_registered(&cdev->dev)) {
+		/* Undo device_add(). */
 		device_del(&cdev->dev);
+	}
+	if (cdev->private->flags.initialized) {
+		cdev->private->flags.initialized = 0;
 		/* Release reference from device_initialize(). */
 		put_device(&cdev->dev);
 	}
@@ -716,6 +720,7 @@
 		put_device(&cdev->dev);
 		return -ENODEV;
 	}
+	cdev->private->flags.initialized = 1;
 	return 0;
 }
 
@@ -998,6 +1003,7 @@
 		cdev = sch_get_cdev(sch);
 		cdev->dev.groups = ccwdev_attr_groups;
 		device_initialize(&cdev->dev);
+		cdev->private->flags.initialized = 1;
 		ccw_device_register(cdev);
 		/*
 		 * Check if the device is already online. If it is
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:22.000000000 +0100
@@ -167,6 +167,7 @@
 		unsigned int resuming:1;    /* recognition while resume */
 		unsigned int pgroup:1;	    /* pathgroup is set up */
 		unsigned int mpath:1;	    /* multipathing is set up */
+		unsigned int initialized:1; /* set if initial reference held */
 	} __attribute__((packed)) flags;
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 46/52] [PATCH] cio: fix quiesce state
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (44 preceding siblings ...)
  2009-11-13 15:09 ` [patch 45/52] [PATCH] cio: add per device initialization status flag Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 47/52] [PATCH] cio: handle failed disable_subchannel after device recognition Martin Schwidefsky
                   ` (6 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 145-cio-fix-quiesce-state.diff --]
[-- Type: text/plain, Size: 3538 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

DEV_STATE_QUIESCE is used to stop all IO on a busy subchannel.
This patch fixes the following problems related to the QUIESCE
state:

* Fix a potential race condition which could occur when the
resulting state was DEV_STATE_OFFLINE.

* Add missing locking around cio_disable_subchannel,
ccw_device_cancel_halt_clear and the cdev's handler.

* Loop until we know for sure that the subchannel is disabled.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c     |   35 +++++++++++++++++++----------------
 drivers/s390/cio/device_fsm.c |   17 ++++-------------
 2 files changed, 23 insertions(+), 29 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
@@ -1130,33 +1130,36 @@
 	return 0;
 }
 
-static void
-io_subchannel_shutdown(struct subchannel *sch)
+static void io_subchannel_shutdown(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 	int ret;
 
+	spin_lock_irq(sch->lock);
 	cdev = sch_get_cdev(sch);
-
 	if (cio_is_console(sch->schid))
-		return;
+		goto out_unlock;
 	if (!sch->schib.pmcw.ena)
-		/* Nothing to do. */
-		return;
+		goto out_unlock;
 	ret = cio_disable_subchannel(sch);
 	if (ret != -EBUSY)
-		/* Subchannel is disabled, we're done. */
-		return;
-	cdev->private->state = DEV_STATE_QUIESCE;
+		goto out_unlock;
 	if (cdev->handler)
-		cdev->handler(cdev, cdev->private->intparm,
-			      ERR_PTR(-EIO));
-	ret = ccw_device_cancel_halt_clear(cdev);
-	if (ret == -EBUSY) {
-		ccw_device_set_timeout(cdev, HZ/10);
-		wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
+		cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO));
+	while (ret == -EBUSY) {
+		cdev->private->state = DEV_STATE_QUIESCE;
+		ret = ccw_device_cancel_halt_clear(cdev);
+		if (ret == -EBUSY) {
+			ccw_device_set_timeout(cdev, HZ/10);
+			spin_unlock_irq(sch->lock);
+			wait_event(cdev->private->wait_q,
+				   cdev->private->state != DEV_STATE_QUIESCE);
+			spin_lock_irq(sch->lock);
+		}
+		ret = cio_disable_subchannel(sch);
 	}
-	cio_disable_subchannel(sch);
+out_unlock:
+	spin_unlock_irq(sch->lock);
 }
 
 static int device_is_disconnected(struct ccw_device *cdev)
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:22.000000000 +0100
@@ -911,10 +911,7 @@
 ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
 {
 	ccw_device_set_timeout(cdev, 0);
-	if (dev_event == DEV_EVENT_NOTOPER)
-		cdev->private->state = DEV_STATE_NOT_OPER;
-	else
-		cdev->private->state = DEV_STATE_OFFLINE;
+	cdev->private->state = DEV_STATE_NOT_OPER;
 	wake_up(&cdev->private->wait_q);
 }
 
@@ -924,17 +921,11 @@
 	int ret;
 
 	ret = ccw_device_cancel_halt_clear(cdev);
-	switch (ret) {
-	case 0:
-		cdev->private->state = DEV_STATE_OFFLINE;
-		wake_up(&cdev->private->wait_q);
-		break;
-	case -ENODEV:
+	if (ret == -EBUSY) {
+		ccw_device_set_timeout(cdev, HZ/10);
+	} else {
 		cdev->private->state = DEV_STATE_NOT_OPER;
 		wake_up(&cdev->private->wait_q);
-		break;
-	default:
-		ccw_device_set_timeout(cdev, HZ/10);
 	}
 }
 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 47/52] [PATCH] cio: handle failed disable_subchannel after device recognition
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (45 preceding siblings ...)
  2009-11-13 15:09 ` [patch 46/52] [PATCH] cio: fix quiesce state Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 48/52] [PATCH] cio: handle busy subchannel in ccw_device_move_to_sch Martin Schwidefsky
                   ` (5 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 146-cio-failed-disable-subchannel.diff --]
[-- Type: text/plain, Size: 1036 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

Handle a failing cio_disable_subchannel at the end of our device
recognition as if the recognition itself failed. This way
subsequent registration steps do not need to handle enabled
subchannels.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device_fsm.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:22.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_fsm.c	2009-11-13 16:08:22.000000000 +0100
@@ -229,7 +229,8 @@
 
 	sch = to_subchannel(cdev->dev.parent);
 
-	cio_disable_subchannel(sch);
+	if (cio_disable_subchannel(sch))
+		state = DEV_STATE_NOT_OPER;
 	/*
 	 * Now that we tried recognition, we have performed device selection
 	 * through ssch() and the path information is up to date.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 48/52] [PATCH] cio: handle busy subchannel in ccw_device_move_to_sch
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (46 preceding siblings ...)
  2009-11-13 15:09 ` [patch 47/52] [PATCH] cio: handle failed disable_subchannel after device recognition Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 49/52] [PATCH] cio: quiesce subchannel in io_subchannel_remove Martin Schwidefsky
                   ` (4 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 147-cio-handle-busy-subchannel.diff --]
[-- Type: text/plain, Size: 2210 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

Try to disable the old subchannel before we ask the driver core
to move the attached device to a new parent. This way we can use
the QUIESCE state during shutdown which prevents a possible use
after free situation in some error cases.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |   24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
@@ -892,12 +892,27 @@
 				  struct subchannel *sch)
 {
 	struct subchannel *old_sch;
-	int rc;
+	int rc, old_enabled = 0;
 
 	old_sch = to_subchannel(cdev->dev.parent);
 	/* Obtain child reference for new parent. */
 	if (!get_device(&sch->dev))
 		return -ENODEV;
+
+	if (!sch_is_pseudo_sch(old_sch)) {
+		spin_lock_irq(old_sch->lock);
+		old_enabled = old_sch->schib.pmcw.ena;
+		rc = 0;
+		if (old_enabled)
+			rc = cio_disable_subchannel(old_sch);
+		spin_unlock_irq(old_sch->lock);
+		if (rc == -EBUSY) {
+			/* Release child reference for new parent. */
+			put_device(&sch->dev);
+			return rc;
+		}
+	}
+
 	mutex_lock(&sch->reg_mutex);
 	rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
 	mutex_unlock(&sch->reg_mutex);
@@ -906,6 +921,12 @@
 			      cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, sch->schid.ssid,
 			      sch->schib.pmcw.dev, rc);
+		if (old_enabled) {
+			/* Try to reenable the old subchannel. */
+			spin_lock_irq(old_sch->lock);
+			cio_enable_subchannel(old_sch, (u32)(addr_t)old_sch);
+			spin_unlock_irq(old_sch->lock);
+		}
 		/* Release child reference for new parent. */
 		put_device(&sch->dev);
 		return rc;
@@ -914,7 +935,6 @@
 	if (!sch_is_pseudo_sch(old_sch)) {
 		spin_lock_irq(old_sch->lock);
 		sch_set_cdev(old_sch, NULL);
-		cio_disable_subchannel(old_sch);
 		spin_unlock_irq(old_sch->lock);
 		css_schedule_eval(old_sch->schid);
 	}

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 49/52] [PATCH] cio: quiesce subchannel in io_subchannel_remove
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (47 preceding siblings ...)
  2009-11-13 15:09 ` [patch 48/52] [PATCH] cio: handle busy subchannel in ccw_device_move_to_sch Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 50/52] [PATCH] cio: change locking " Martin Schwidefsky
                   ` (3 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 148-cio-quiesce-subchannel.diff --]
[-- Type: text/plain, Size: 1512 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

Ensure that there will be no more interrupts for an
unregistered device by using the same quiesce and disable loop
as in io_subchannel_shutdown.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
@@ -1059,6 +1059,8 @@
 	return 0;
 }
 
+static void io_subchannel_quiesce(struct subchannel *);
+
 static int
 io_subchannel_remove (struct subchannel *sch)
 {
@@ -1068,6 +1070,7 @@
 	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		goto out_free;
+	io_subchannel_quiesce(sch);
 	/* Set ccw device to not operational and drop reference. */
 	spin_lock_irqsave(cdev->ccwlock, flags);
 	sch_set_cdev(sch, NULL);
@@ -1150,7 +1153,7 @@
 	return 0;
 }
 
-static void io_subchannel_shutdown(struct subchannel *sch)
+static void io_subchannel_quiesce(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 	int ret;
@@ -1182,6 +1185,11 @@
 	spin_unlock_irq(sch->lock);
 }
 
+static void io_subchannel_shutdown(struct subchannel *sch)
+{
+	io_subchannel_quiesce(sch);
+}
+
 static int device_is_disconnected(struct ccw_device *cdev)
 {
 	if (!cdev)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 50/52] [PATCH] cio: change locking in io_subchannel_remove
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (48 preceding siblings ...)
  2009-11-13 15:09 ` [patch 49/52] [PATCH] cio: quiesce subchannel in io_subchannel_remove Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 51/52] [PATCH] cio: improve error recovery for internal I/Os Martin Schwidefsky
                   ` (2 subsequent siblings)
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 149-cio-subchannel-locking.diff --]
[-- Type: text/plain, Size: 1218 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

IO subchannels are always unregistered in process context, so use
spin_lock_irq in the corresponding remove callback.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:22.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:23.000000000 +0100
@@ -1065,17 +1065,16 @@
 io_subchannel_remove (struct subchannel *sch)
 {
 	struct ccw_device *cdev;
-	unsigned long flags;
 
 	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		goto out_free;
 	io_subchannel_quiesce(sch);
 	/* Set ccw device to not operational and drop reference. */
-	spin_lock_irqsave(cdev->ccwlock, flags);
+	spin_lock_irq(cdev->ccwlock);
 	sch_set_cdev(sch, NULL);
 	cdev->private->state = DEV_STATE_NOT_OPER;
-	spin_unlock_irqrestore(cdev->ccwlock, flags);
+	spin_unlock_irq(cdev->ccwlock);
 	ccw_device_unregister(cdev);
 out_free:
 	kfree(sch->private);

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 51/52] [PATCH] cio: improve error recovery for internal I/Os
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (49 preceding siblings ...)
  2009-11-13 15:09 ` [patch 50/52] [PATCH] cio: change locking " Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:09 ` [patch 52/52] [PATCH] cio: dont unregister a busy device in ccw_device_set_offline Martin Schwidefsky
  2009-11-13 15:28 ` [patch 00/52] s390 patches for the next merge window (2.6.33) Arnd Bergmann
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Peter Oberparleiter, Martin Schwidefsky

[-- Attachment #1: 150-cio-internal-errors.diff --]
[-- Type: text/plain, Size: 3204 bytes --]

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

Improve error recovery for internal I/Os by repeating each I/O
256 times per path to cope with long-running non-permanent error
conditions. Also retry each path twice to cope with link flapping,
i.e. single paths becoming unavailable in the order in which they
are tried.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/ccwreq.c      |    7 ++++---
 drivers/s390/cio/device_id.c   |    2 +-
 drivers/s390/cio/device_pgid.c |    2 +-
 drivers/s390/cio/io_sch.h      |    2 +-
 4 files changed, 7 insertions(+), 6 deletions(-)

Index: quilt-2.6/drivers/s390/cio/ccwreq.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/ccwreq.c	2009-11-13 16:08:19.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/ccwreq.c	2009-11-13 16:08:23.000000000 +0100
@@ -82,7 +82,7 @@
 		/* Perform start function. */
 		sch->lpm = 0xff;
 		memset(&cdev->private->irb, 0, sizeof(struct irb));
-		rc = cio_start(sch, cp, req->mask);
+		rc = cio_start(sch, cp, (u8) req->mask);
 		if (rc == 0) {
 			/* I/O started successfully. */
 			ccw_device_set_timeout(cdev, req->timeout);
@@ -116,7 +116,8 @@
 {
 	struct ccw_request *req = &cdev->private->req;
 
-	req->mask	= 0x80;
+	/* Try all paths twice to counter link flapping. */
+	req->mask	= 0x8080;
 	req->retries	= req->maxretries;
 	req->mask	= lpm_adjust(req->mask, req->lpm);
 	req->drc	= 0;
@@ -212,7 +213,7 @@
 	}  __attribute__ ((packed)) data;
 	data.dev_id	= cdev->private->dev_id;
 	data.retries	= req->retries;
-	data.lpm	= req->mask;
+	data.lpm	= (u8) req->mask;
 	data.status	= (u8) status;
 	CIO_TRACE_EVENT(2, "reqstat");
 	CIO_HEX_EVENT(2, &data, sizeof(data));
Index: quilt-2.6/drivers/s390/cio/device_id.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_id.c	2009-11-13 16:08:20.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_id.c	2009-11-13 16:08:23.000000000 +0100
@@ -21,7 +21,7 @@
 #include "device.h"
 #include "io_sch.h"
 
-#define SENSE_ID_RETRIES	5
+#define SENSE_ID_RETRIES	256
 #define SENSE_ID_TIMEOUT	(10 * HZ)
 #define SENSE_ID_MIN_LEN	4
 #define SENSE_ID_BASIC_LEN	7
Index: quilt-2.6/drivers/s390/cio/device_pgid.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:21.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device_pgid.c	2009-11-13 16:08:23.000000000 +0100
@@ -20,7 +20,7 @@
 #include "device.h"
 #include "io_sch.h"
 
-#define PGID_RETRIES	5
+#define PGID_RETRIES	256
 #define PGID_TIMEOUT	(10 * HZ)
 
 /*
Index: quilt-2.6/drivers/s390/cio/io_sch.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/io_sch.h	2009-11-13 16:08:22.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/io_sch.h	2009-11-13 16:08:23.000000000 +0100
@@ -109,7 +109,7 @@
 	void (*callback)(struct ccw_device *, void *, int);
 	void *data;
 	/* These fields are used internally. */
-	u8 mask;
+	u16 mask;
 	u16 retries;
 	int drc;
 	int cancel:1;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [patch 52/52] [PATCH] cio: dont unregister a busy device in ccw_device_set_offline
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (50 preceding siblings ...)
  2009-11-13 15:09 ` [patch 51/52] [PATCH] cio: improve error recovery for internal I/Os Martin Schwidefsky
@ 2009-11-13 15:09 ` Martin Schwidefsky
  2009-11-13 15:28 ` [patch 00/52] s390 patches for the next merge window (2.6.33) Arnd Bergmann
  52 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-13 15:09 UTC (permalink / raw)
  To: linux-kernel, linux-s390
  Cc: Heiko Carstens, Sebastian Ott, Martin Schwidefsky

[-- Attachment #1: 151-cio-busy-device-unregister.diff --]
[-- Type: text/plain, Size: 2844 bytes --]

From: Sebastian Ott <sebott@linux.vnet.ibm.com>

If we detect a busy subchannel after the driver's set_offline
callback returned in ccw_device_set_offline, the current behavior
is to unregister the device, which may lead to undesired
consequences. Change this to just quiesce the subchannel and go on
with the offline processing.

Note: This is no excuse for not fixing these drivers -
after the set_offline callback they should have no running IO!

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 drivers/s390/cio/device.c |   29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

Index: quilt-2.6/drivers/s390/cio/device.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device.c	2009-11-13 16:08:23.000000000 +0100
+++ quilt-2.6/drivers/s390/cio/device.c	2009-11-13 16:08:23.000000000 +0100
@@ -314,6 +314,8 @@
 	}
 }
 
+static void io_subchannel_quiesce(struct subchannel *);
+
 /**
  * ccw_device_set_offline() - disable a ccw device for I/O
  * @cdev: target ccw device
@@ -327,7 +329,8 @@
  */
 int ccw_device_set_offline(struct ccw_device *cdev)
 {
-	int ret;
+	struct subchannel *sch;
+	int ret, state;
 
 	if (!cdev)
 		return -ENODEV;
@@ -341,6 +344,7 @@
 	}
 	cdev->online = 0;
 	spin_lock_irq(cdev->ccwlock);
+	sch = to_subchannel(cdev->dev.parent);
 	/* Wait until a final state or DISCONNECTED is reached */
 	while (!dev_fsm_final_state(cdev) &&
 	       cdev->private->state != DEV_STATE_DISCONNECTED) {
@@ -349,9 +353,21 @@
 			   cdev->private->state == DEV_STATE_DISCONNECTED));
 		spin_lock_irq(cdev->ccwlock);
 	}
-	ret = ccw_device_offline(cdev);
-	if (ret)
-		goto error;
+	do {
+		ret = ccw_device_offline(cdev);
+		if (!ret)
+			break;
+		CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device "
+			      "0.%x.%04x\n", ret, cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
+		if (ret != -EBUSY)
+			goto error;
+		state = cdev->private->state;
+		spin_unlock_irq(cdev->ccwlock);
+		io_subchannel_quiesce(sch);
+		spin_lock_irq(cdev->ccwlock);
+		cdev->private->state = state;
+	} while (ret == -EBUSY);
 	spin_unlock_irq(cdev->ccwlock);
 	wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
 		   cdev->private->state == DEV_STATE_DISCONNECTED));
@@ -368,9 +384,6 @@
 	return 0;
 
 error:
-	CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
-		      ret, cdev->private->dev_id.ssid,
-		      cdev->private->dev_id.devno);
 	cdev->private->state = DEV_STATE_OFFLINE;
 	dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 	spin_unlock_irq(cdev->ccwlock);
@@ -1059,8 +1072,6 @@
 	return 0;
 }
 
-static void io_subchannel_quiesce(struct subchannel *);
-
 static int
 io_subchannel_remove (struct subchannel *sch)
 {

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [patch 00/52] s390 patches for the next merge window (2.6.33)
  2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
                   ` (51 preceding siblings ...)
  2009-11-13 15:09 ` [patch 52/52] [PATCH] cio: dont unregister a busy device in ccw_device_set_offline Martin Schwidefsky
@ 2009-11-13 15:28 ` Arnd Bergmann
  2009-11-13 15:31   ` s390: move keyboard compat ioctls into tty3270 driver Arnd Bergmann
  52 siblings, 1 reply; 56+ messages in thread
From: Arnd Bergmann @ 2009-11-13 15:28 UTC (permalink / raw)
  To: Martin Schwidefsky; +Cc: linux-kernel, linux-s390, Heiko Carstens

I have one pending for the tty3270 driver, will resend.

	Arnd <><

^ permalink raw reply	[flat|nested] 56+ messages in thread

* s390: move keyboard compat ioctls into tty3270 driver
  2009-11-13 15:28 ` [patch 00/52] s390 patches for the next merge window (2.6.33) Arnd Bergmann
@ 2009-11-13 15:31   ` Arnd Bergmann
  2009-11-16  8:33     ` Martin Schwidefsky
  0 siblings, 1 reply; 56+ messages in thread
From: Arnd Bergmann @ 2009-11-13 15:31 UTC (permalink / raw)
  To: Martin Schwidefsky; +Cc: linux-kernel, linux-s390, Heiko Carstens

All keyboard ioctls are compatible, so we can simply
move the compat handling into the vt and tty3270 drivers.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 3838567..86b2889 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -1731,6 +1731,22 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file,
 	return kbd_ioctl(tp->kbd, file, cmd, arg);
 }
 
+#ifdef CONFIG_COMPAT
+static long
+tty3270_compat_ioctl(struct tty_struct *tty, struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+	struct tty3270 *tp;
+
+	tp = tty->driver_data;
+	if (!tp)
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+	return kbd_ioctl(tp->kbd, file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 static const struct tty_operations tty3270_ops = {
 	.open = tty3270_open,
 	.close = tty3270_close,
@@ -1745,6 +1761,9 @@ static const struct tty_operations tty3270_ops = {
 	.hangup = tty3270_hangup,
 	.wait_until_sent = tty3270_wait_until_sent,
 	.ioctl = tty3270_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = tty3270_compat_ioctl,
+#endif
 	.set_termios = tty3270_set_termios
 };
 

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: s390: move keyboard compat ioctls into tty3270 driver
  2009-11-13 15:31   ` s390: move keyboard compat ioctls into tty3270 driver Arnd Bergmann
@ 2009-11-16  8:33     ` Martin Schwidefsky
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Schwidefsky @ 2009-11-16  8:33 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-kernel, linux-s390, Heiko Carstens

On Fri, 13 Nov 2009 16:31:17 +0100
Arnd Bergmann <arnd@arndb.de> wrote:

> All keyboard ioctls are compatible, so we can simply
> move the compat handling into the vt and tty3270 drivers.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

I'll add the patch to the queue. Thanks ..

-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2009-11-16  8:33 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-13 15:08 [patch 00/52] s390 patches for the next merge window (2.6.33) Martin Schwidefsky
2009-11-13 15:08 ` [patch 01/52] [PATCH] Improve address space check Martin Schwidefsky
2009-11-13 15:08 ` [patch 02/52] [PATCH] Improve address space mode selection Martin Schwidefsky
2009-11-13 15:08 ` [patch 03/52] [PATCH] Improve notify_page_fault implementation Martin Schwidefsky
2009-11-13 15:08 ` [patch 04/52] [PATCH] fault handler performance optimization Martin Schwidefsky
2009-11-13 15:08 ` [patch 05/52] [PATCH] fault handler access flags check Martin Schwidefsky
2009-11-13 15:08 ` [patch 06/52] [PATCH] Use do_exception() in pagetable walk usercopy functions Martin Schwidefsky
2009-11-13 15:08 ` [patch 07/52] [PATCH] Improve code generated by atomic operations Martin Schwidefsky
2009-11-13 15:08 ` [patch 08/52] [PATCH] dasd: support DIAG access for read-only devices Martin Schwidefsky
2009-11-13 15:08 ` [patch 09/52] [PATCH] cmm: free pages on hibernate Martin Schwidefsky
2009-11-13 15:08 ` [patch 10/52] [PATCH] smp: remove unused typedef and defines Martin Schwidefsky
2009-11-13 15:08 ` [patch 11/52] [PATCH] dasd: remove dead code Martin Schwidefsky
2009-11-13 15:08 ` [patch 12/52] [PATCH] use generic termbits.h header file Martin Schwidefsky
2009-11-13 15:08 ` [patch 13/52] [PATCH] use generic sockios.h " Martin Schwidefsky
2009-11-13 15:08 ` [patch 14/52] [PATCH] MAINTAINERS: Add s390 drivers block Martin Schwidefsky
2009-11-13 15:08 ` [patch 15/52] [PATCH] zcrypt: initialize ap_messages for cex3 exploitation Martin Schwidefsky
2009-11-13 15:08 ` [patch 16/52] [PATCH] zcrypt: special command support " Martin Schwidefsky
2009-11-13 15:08 ` [patch 17/52] [PATCH] zcrypt: add support for cex3 device types Martin Schwidefsky
2009-11-13 15:08 ` [patch 18/52] [PATCH] zcrypt: use definitions for cex3 Martin Schwidefsky
2009-11-13 15:08 ` [patch 19/52] [PATCH] zcrypt: adjust speed rating between cex2 and pcixcc Martin Schwidefsky
2009-11-13 15:08 ` [patch 20/52] [PATCH] zcrypt: adjust speed rating of cex3 adapters Martin Schwidefsky
2009-11-13 15:08 ` [patch 21/52] [PATCH] dasd: enable prefix independent of pav support Martin Schwidefsky
2009-11-13 15:08 ` [patch 22/52] [PATCH] dasd: improve error recovery for internal I/O Martin Schwidefsky
2009-11-13 15:08 ` [patch 23/52] [PATCH] dasd: remove strings from s390dbf Martin Schwidefsky
2009-11-13 15:08 ` [patch 24/52] [PATCH] s390: use change recording override for kernel mapping Martin Schwidefsky
2009-11-13 15:08 ` [patch 25/52] [PATCH] sclp: improve servicability setting Martin Schwidefsky
2009-11-13 15:08 ` [patch 26/52] [PATCH] cio: fix double free in case of probe failure Martin Schwidefsky
2009-11-13 15:08 ` [patch 27/52] [PATCH] cio: fix repeat setting of cdev parent association Martin Schwidefsky
2009-11-13 15:08 ` [patch 28/52] [PATCH] cio: introduce parent-initiated device move Martin Schwidefsky
2009-11-13 15:08 ` [patch 29/52] [PATCH] cio: introduce subchannel todos Martin Schwidefsky
2009-11-13 15:08 ` [patch 30/52] [PATCH] cio: introduce ccw device todos Martin Schwidefsky
2009-11-13 15:08 ` [patch 31/52] [PATCH] cio: inform user when online/offline processing fails Martin Schwidefsky
2009-11-13 15:08 ` [patch 32/52] [PATCH] cio: handle error during device recognition consistently Martin Schwidefsky
2009-11-13 15:08 ` [patch 33/52] [PATCH] cio: handle error during path verification consistently Martin Schwidefsky
2009-11-13 15:08 ` [patch 34/52] [PATCH] cio: ensure proper locking during device recognition Martin Schwidefsky
2009-11-13 15:08 ` [patch 35/52] [PATCH] cio: dont panic in non-fatal conditions Martin Schwidefsky
2009-11-13 15:09 ` [patch 36/52] [PATCH] cio: consistent infrastructure for internal I/O requests Martin Schwidefsky
2009-11-13 15:09 ` [patch 37/52] [PATCH] cio: use ccw request infrastructure for sense id Martin Schwidefsky
2009-11-13 15:09 ` [patch 38/52] [PATCH] cio: use ccw request infrastructure for pgid Martin Schwidefsky
2009-11-13 15:09 ` [patch 39/52] [PATCH] cio: allow setting not-operational devices offline Martin Schwidefsky
2009-11-13 15:09 ` [patch 40/52] [PATCH] cio: remove intretry flag Martin Schwidefsky
2009-11-13 15:09 ` [patch 41/52] [PATCH] cio: split PGID settings and status Martin Schwidefsky
2009-11-13 15:09 ` [patch 42/52] [PATCH] cio: use sense-pgid operation for path verification Martin Schwidefsky
2009-11-13 15:09 ` [patch 43/52] [PATCH] cio: make steal lock procedure more robust Martin Schwidefsky
2009-11-13 15:09 ` [patch 44/52] [PATCH] cio: remove registered flag from ccw_device_private Martin Schwidefsky
2009-11-13 15:09 ` [patch 45/52] [PATCH] cio: add per device initialization status flag Martin Schwidefsky
2009-11-13 15:09 ` [patch 46/52] [PATCH] cio: fix quiesce state Martin Schwidefsky
2009-11-13 15:09 ` [patch 47/52] [PATCH] cio: handle failed disable_subchannel after device recognition Martin Schwidefsky
2009-11-13 15:09 ` [patch 48/52] [PATCH] cio: handle busy subchannel in ccw_device_move_to_sch Martin Schwidefsky
2009-11-13 15:09 ` [patch 49/52] [PATCH] cio: quiesce subchannel in io_subchannel_remove Martin Schwidefsky
2009-11-13 15:09 ` [patch 50/52] [PATCH] cio: change locking " Martin Schwidefsky
2009-11-13 15:09 ` [patch 51/52] [PATCH] cio: improve error recovery for internal I/Os Martin Schwidefsky
2009-11-13 15:09 ` [patch 52/52] [PATCH] cio: dont unregister a busy device in ccw_device_set_offline Martin Schwidefsky
2009-11-13 15:28 ` [patch 00/52] s390 patches for the next merge window (2.6.33) Arnd Bergmann
2009-11-13 15:31   ` s390: move keyboard compat ioctls into tty3270 driver Arnd Bergmann
2009-11-16  8:33     ` Martin Schwidefsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).