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

From: Utz Bacher <utz.bacher@de.ibm.com>
From: Cornelia Huck <cohuck@de.ibm.com>

Common i/o layer changes:
 - Consolidate store channel subsystem characteristics from its three
   users (css, cmf and qdio) to a single location.
 - Always use new stipd format and move creation of global path group
   to channel subsystem init function. Add dummy init_IRQ to setup.c
   and remove requestirq.c.
 - Remove bogus CHPID_LONGS define.
 - Add more magic to catch chpids coming online again without generating
   machine checks.
 - Fix check for unsolicited interrupts. Deferred cc=1 indicates a
   solicited interrupt.
 - Fix progress indication in qdio summary bytes to avoid loosing interrupts.
 - Rename console_device to console_devno to avoid naming conflict.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 /dev/null                                |   45 ---------------
 25-akpm/arch/s390/kernel/head.S          |    4 -
 25-akpm/arch/s390/kernel/head64.S        |    4 -
 25-akpm/arch/s390/kernel/s390_ksyms.c    |    3 -
 25-akpm/arch/s390/kernel/setup.c         |   16 ++++-
 25-akpm/drivers/s390/cio/Makefile        |    2 
 25-akpm/drivers/s390/cio/chsc.c          |   58 +++++++++++++++++++
 25-akpm/drivers/s390/cio/chsc.h          |   28 +++++++++
 25-akpm/drivers/s390/cio/cio.c           |    6 +-
 25-akpm/drivers/s390/cio/cmf.c           |    6 +-
 25-akpm/drivers/s390/cio/css.c           |   47 +++++++++++++++-
 25-akpm/drivers/s390/cio/device_fsm.c    |   47 ++++++++--------
 25-akpm/drivers/s390/cio/device_id.c     |   13 ++--
 25-akpm/drivers/s390/cio/device_ops.c    |    2 
 25-akpm/drivers/s390/cio/device_pgid.c   |   28 ++++-----
 25-akpm/drivers/s390/cio/device_status.c |    7 +-
 25-akpm/drivers/s390/cio/qdio.c          |   90 +++++++++++--------------------
 25-akpm/drivers/s390/cio/qdio.h          |    4 +
 25-akpm/include/asm-s390/setup.h         |    3 -
 19 files changed, 239 insertions(+), 174 deletions(-)

diff -puN arch/s390/kernel/head64.S~s390-comon-i-o-layer arch/s390/kernel/head64.S
--- 25/arch/s390/kernel/head64.S~s390-comon-i-o-layer	2004-06-30 10:16:33.417679576 -0700
+++ 25-akpm/arch/s390/kernel/head64.S	2004-06-30 10:16:33.451674408 -0700
@@ -623,10 +623,6 @@ startup:basr  %r13,0                    
         bne    1f-.LPG1(%r13)
         oi     7(%r12),4                # set P/390 flag
 1:
-	chi    %r0,0x2084		# new stidp format?
-	bne    2f-.LPG1(%r13)
-	oi     7(%r12),64		# set new stidp flag
-2:	
 
 #
 # find out if we have the MVPG instruction
diff -puN arch/s390/kernel/head.S~s390-comon-i-o-layer arch/s390/kernel/head.S
--- 25/arch/s390/kernel/head.S~s390-comon-i-o-layer	2004-06-30 10:16:33.419679272 -0700
+++ 25-akpm/arch/s390/kernel/head.S	2004-06-30 10:16:33.450674560 -0700
@@ -613,10 +613,6 @@ startup:basr  %r13,0                    
         bne    .Lnop390-.LPG1(%r13)
         oi     3(%r12),4                # set P/390 flag
 .Lnop390:
-	chi    %r0,0x2084		# new stidp format?
-	bne    .Loldfmt-.LPG1(%r13)
-	oi     3(%r12),64		# set new stidp flag
-.Loldfmt:	
 
 #
 # find out if we have an IEEE fpu
diff -puN arch/s390/kernel/s390_ksyms.c~s390-comon-i-o-layer arch/s390/kernel/s390_ksyms.c
--- 25/arch/s390/kernel/s390_ksyms.c~s390-comon-i-o-layer	2004-06-30 10:16:33.420679120 -0700
+++ 25-akpm/arch/s390/kernel/s390_ksyms.c	2004-06-30 10:16:33.451674408 -0700
@@ -72,7 +72,8 @@ EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(console_mode);
-EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL(console_devno);
+EXPORT_SYMBOL(console_irq);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
 EXPORT_SYMBOL(sys_wait4);
 EXPORT_SYMBOL(cpcmd);
diff -puN arch/s390/kernel/setup.c~s390-comon-i-o-layer arch/s390/kernel/setup.c
--- 25/arch/s390/kernel/setup.c~s390-comon-i-o-layer	2004-06-30 10:16:33.422678816 -0700
+++ 25-akpm/arch/s390/kernel/setup.c	2004-06-30 10:16:33.452674256 -0700
@@ -49,7 +49,7 @@
  * Machine setup..
  */
 unsigned int console_mode = 0;
-unsigned int console_device = -1;
+unsigned int console_devno = -1;
 unsigned int console_irq = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
@@ -160,7 +160,7 @@ static int __init condev_setup(char *str
 
 	vdev = simple_strtoul(str, &str, 0);
 	if (vdev >= 0 && vdev < 65536) {
-		console_device = vdev;
+		console_devno = vdev;
 		console_irq = -1;
 	}
 	return 1;
@@ -194,7 +194,7 @@ static void __init conmode_default(void)
 
         if (MACHINE_IS_VM) {
 		cpcmd("QUERY CONSOLE", query_buffer, 1024);
-		console_device = simple_strtoul(query_buffer + 5, NULL, 16);
+		console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
 		ptr = strstr(query_buffer, "SUBCHANNEL =");
 		console_irq = simple_strtoul(ptr + 13, NULL, 16);
 		cpcmd("QUERY TERM", query_buffer, 1024);
@@ -649,3 +649,13 @@ int show_interrupts(struct seq_file *p, 
 	
         return 0;
 }
+
+/*
+ * For compatibilty only. S/390 specific setup of interrupts et al. is done
+ * much later in init_channel_subsystem().
+ */
+void __init
+init_IRQ(void)
+{
+	/* nothing... */
+}
diff -puN drivers/s390/cio/chsc.c~s390-comon-i-o-layer drivers/s390/cio/chsc.c
--- 25/drivers/s390/cio/chsc.c~s390-comon-i-o-layer	2004-06-30 10:16:33.423678664 -0700
+++ 25-akpm/drivers/s390/cio/chsc.c	2004-06-30 10:16:33.453674104 -0700
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.112 $
+ *   $Revision: 1.114 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -942,3 +942,59 @@ chsc_alloc_sei_area(void)
 }
 
 subsys_initcall(chsc_alloc_sei_area);
+
+struct css_general_char css_general_characteristics;
+struct css_chsc_char css_chsc_characteristics;
+
+int __init
+chsc_determine_css_characteristics(void)
+{
+	int result;
+	struct {
+		struct chsc_header request;
+		u32 reserved1;
+		u32 reserved2;
+		u32 reserved3;
+		struct chsc_header response;
+		u32 reserved4;
+		u32 general_char[510];
+		u32 chsc_char[518];
+	} *scsc_area;
+
+	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!scsc_area) {
+	        printk(KERN_WARNING"cio: Was not able to determine available" \
+		       "CHSCs due to no memory.\n");
+		return -ENOMEM;
+	}
+
+	scsc_area->request = (struct chsc_header) {
+		.length = 0x0010,
+		.code   = 0x0010,
+	};
+
+	result = chsc(scsc_area);
+	if (result) {
+		printk(KERN_WARNING"cio: Was not able to determine " \
+		       "available CHSCs, cc=%i.\n", result);
+		result = -EIO;
+		goto exit;
+	}
+
+	if (scsc_area->response.code != 1) {
+		printk(KERN_WARNING"cio: Was not able to determine " \
+		       "available CHSCs.\n");
+		result = -EIO;
+		goto exit;
+	}
+	memcpy(&css_general_characteristics, scsc_area->general_char,
+	       sizeof(css_general_characteristics));
+	memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
+	       sizeof(css_chsc_characteristics));
+exit:
+	free_page ((unsigned long) scsc_area);
+	return result;
+}
+
+EXPORT_SYMBOL_GPL(css_general_characteristics);
+EXPORT_SYMBOL_GPL(css_chsc_characteristics);
diff -puN drivers/s390/cio/chsc.h~s390-comon-i-o-layer drivers/s390/cio/chsc.h
--- 25/drivers/s390/cio/chsc.h~s390-comon-i-o-layer	2004-06-30 10:16:33.424678512 -0700
+++ 25-akpm/drivers/s390/cio/chsc.h	2004-06-30 10:16:33.454673952 -0700
@@ -23,4 +23,32 @@ extern struct channel_path *chps[];
 extern void s390_process_css( void );
 extern void chsc_validate_chpids(struct subchannel *);
 extern void chpid_is_actually_online(int);
+
+struct css_general_char {
+	u64 : 41;
+	u32 aif : 1;     /* bit 41 */
+	u32 : 3;
+	u32 mcss : 1;    /* bit 45 */
+	u32 : 2;
+	u32 ext_mb : 1;  /* bit 48 */
+	u32 : 7;
+	u32 aif_tdd : 1; /* bit 56 */
+	u32 : 10;
+	u32 aif_osa : 1; /* bit 67 */
+	u32 : 28;
+}__attribute__((packed));
+
+struct css_chsc_char {
+	u64 res;
+	u64 : 43;
+	u32 scssc : 1;  /* bit 107 */
+	u32 scsscf : 1; /* bit 108 */
+	u32 : 19;
+}__attribute__((packed));
+
+extern struct css_general_char css_general_characteristics;
+extern struct css_chsc_char css_chsc_characteristics;
+
+extern int chsc_determine_css_characteristics(void);
+extern int css_characteristics_avail;
 #endif
diff -puN drivers/s390/cio/cio.c~s390-comon-i-o-layer drivers/s390/cio/cio.c
--- 25/drivers/s390/cio/cio.c~s390-comon-i-o-layer	2004-06-30 10:16:33.426678208 -0700
+++ 25-akpm/drivers/s390/cio/cio.c	2004-06-30 10:16:33.455673800 -0700
@@ -688,15 +688,15 @@ cio_console_irq(void)
 		if (stsch(console_irq, &console_subchannel.schib) != 0 ||
 		    !console_subchannel.schib.pmcw.dnv)
 			return -1;
-		console_device = console_subchannel.schib.pmcw.dev;
-	} else if (console_device != -1) {
+		console_devno = console_subchannel.schib.pmcw.dev;
+	} else if (console_devno != -1) {
 		/* At least the console device number is known. */
 		for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
 			if (stsch(irq, &console_subchannel.schib) != 0)
 				break;
 			if (console_subchannel.schib.pmcw.dnv &&
 			    console_subchannel.schib.pmcw.dev ==
-			    console_device) {
+			    console_devno) {
 				console_irq = irq;
 				break;
 			}
diff -puN drivers/s390/cio/cmf.c~s390-comon-i-o-layer drivers/s390/cio/cmf.c
--- 25/drivers/s390/cio/cmf.c~s390-comon-i-o-layer	2004-06-30 10:16:33.427678056 -0700
+++ 25-akpm/drivers/s390/cio/cmf.c	2004-06-30 10:16:33.456673648 -0700
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/s390/cio/cmf.c ($Revision: 1.13 $)
+ * linux/drivers/s390/cio/cmf.c ($Revision: 1.15 $)
  *
  * Linux on zSeries Channel Measurement Facility support
  *
@@ -39,6 +39,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "chsc.h"
 
 /* parameter to enable cmf during boot, possible uses are:
  *  "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
@@ -996,7 +997,8 @@ init_cmf(void)
 	   see if we are running on z990 or up, otherwise fall back to basic mode. */
 
 	if (format == CMF_AUTODETECT) {
-		if (!MACHINE_NEW_STIDP) {
+		if (!css_characteristics_avail ||
+		    !css_general_characteristics.ext_mb) {
 			format = CMF_BASIC;
 		} else {
 			format = CMF_EXTENDED;
diff -puN drivers/s390/cio/css.c~s390-comon-i-o-layer drivers/s390/cio/css.c
--- 25/drivers/s390/cio/css.c~s390-comon-i-o-layer	2004-06-30 10:16:33.433677144 -0700
+++ 25-akpm/drivers/s390/cio/css.c	2004-06-30 10:16:33.457673496 -0700
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.77 $
+ *   $Revision: 1.80 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -19,11 +19,15 @@
 #include "cio.h"
 #include "cio_debug.h"
 #include "ioasm.h"
+#include "chsc.h"
 
 unsigned int highest_subchannel;
 int need_rescan = 0;
 int css_init_done = 0;
 
+struct pgid global_pgid;
+int css_characteristics_avail = 0;
+
 struct device css_bus_device = {
 	.bus_id = "css0",
 };
@@ -201,6 +205,20 @@ css_evaluate_subchannel(int irq, int slo
 			ret = 0;
 			break;
 		}
+		if (disc && (event == CIO_NO_PATH)) {
+			/*
+			 * Uargh, hack again. Because we don't get a machine
+			 * check on configure on, our path bookkeeping can
+			 * be out of date here (it's fine while we only do
+			 * logical varying or get chsc machine checks). We
+			 * need to force reprobing or we might miss devices
+			 * coming operational again. It won't do harm in real
+			 * no path situations.
+			 */
+			device_trigger_reprobe(sch);
+			ret = 0;
+			break;
+		}
 		if (sch->driver && sch->driver->notify &&
 		    sch->driver->notify(&sch->dev, event)) {
 			cio_disable_subchannel(sch);
@@ -352,9 +370,26 @@ css_process_crw(int irq)
 	return ret;
 }
 
+static void __init
+css_generate_pgid(void)
+{
+	/* Let's build our path group ID here. */
+	if (css_characteristics_avail && css_general_characteristics.mcss)
+		global_pgid.cpu_addr = 0x8000;
+	else {
+#ifdef CONFIG_SMP
+		global_pgid.cpu_addr = hard_smp_processor_id();
+#else
+		global_pgid.cpu_addr = 0;
+#endif
+	}
+	global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
+	global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
+	global_pgid.tod_high = (__u32) (get_clock() >> 32);
+}
+
 /*
- * some of the initialization has already been done from init_IRQ(),
- * here we do the rest now that the driver core is running.
+ * Now that the driver core is running, we can setup our channel subsystem.
  * The struct subchannel's are created during probing (except for the
  * static console subchannel).
  */
@@ -363,6 +398,11 @@ init_channel_subsystem (void)
 {
 	int ret, irq;
 
+	if (chsc_determine_css_characteristics() == 0)
+		css_characteristics_avail = 1;
+
+	css_generate_pgid();
+
 	if ((ret = bus_register(&css_bus_type)))
 		goto out;
 	if ((ret = device_register (&css_bus_device)))
@@ -517,3 +557,4 @@ MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(css_bus_type);
 EXPORT_SYMBOL(s390_root_dev_register);
 EXPORT_SYMBOL(s390_root_dev_unregister);
+EXPORT_SYMBOL_GPL(css_characteristics_avail);
diff -puN drivers/s390/cio/device_fsm.c~s390-comon-i-o-layer drivers/s390/cio/device_fsm.c
--- 25/drivers/s390/cio/device_fsm.c~s390-comon-i-o-layer	2004-06-30 10:16:33.434676992 -0700
+++ 25-akpm/drivers/s390/cio/device_fsm.c	2004-06-30 10:16:33.458673344 -0700
@@ -672,8 +672,20 @@ ccw_device_irq(struct ccw_device *cdev, 
 
 	irb = (struct irb *) __LC_IRB;
 	/* Check for unsolicited interrupt. */
-	if (irb->scsw.stctl ==
-	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
+	if ((irb->scsw.stctl ==
+	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+	    && (!irb->scsw.cc)) {
+		if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+		    !irb->esw.esw0.erw.cons) {
+			/* Unit check but no sense data. Need basic sense. */
+			if (ccw_device_do_sense(cdev, irb) != 0)
+				goto call_handler_unsol;
+			memcpy(irb, &cdev->private->irb, sizeof(struct irb));
+			cdev->private->state = DEV_STATE_W4SENSE;
+			cdev->private->intparm = 0;
+			return;
+		}
+call_handler_unsol:
 		if (cdev->handler)
 			cdev->handler (cdev, 0, irb);
 		return;
@@ -735,11 +747,15 @@ ccw_device_w4sense(struct ccw_device *cd
 	/* Check for unsolicited interrupt. */
 	if (irb->scsw.stctl ==
 	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if (cdev->handler)
-			cdev->handler (cdev, 0, irb);
 		if (irb->scsw.cc == 1)
 			/* Basic sense hasn't started. Try again. */
 			ccw_device_do_sense(cdev, irb);
+		else {
+			printk("Huh? %s(%s): unsolicited interrupt...\n",
+			       __FUNCTION__, cdev->dev.bus_id);
+			if (cdev->handler)
+				cdev->handler (cdev, 0, irb);
+		}
 		return;
 	}
 	/* Add basic sense info to irb. */
@@ -762,13 +778,6 @@ ccw_device_clear_verify(struct ccw_devic
 	struct irb *irb;
 
 	irb = (struct irb *) __LC_IRB;
-	/* Check for unsolicited interrupt. */
-	if (irb->scsw.stctl ==
-	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if (cdev->handler)
-			cdev->handler (cdev, 0, irb);
-		return;
-	}
 	/* Accumulate status. We don't do basic sense. */
 	ccw_device_accumulate_irb(cdev, irb);
 	/* Try to start delayed device verification. */
@@ -834,15 +843,6 @@ ccw_device_wait4io_irq(struct ccw_device
 	struct subchannel *sch;
 
 	irb = (struct irb *) __LC_IRB;
-	/* Check for unsolicited interrupt. */
-	if (irb->scsw.stctl ==
-	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		if (cdev->handler)
-			cdev->handler (cdev, 0, irb);
-		if (irb->scsw.cc == 1)
-			goto call_handler;
-		return;
-	}
 	/*
 	 * Accumulate status and find out if a basic sense is needed.
 	 * This is fine since we have already adapted the lpm.
@@ -854,7 +854,7 @@ ccw_device_wait4io_irq(struct ccw_device
 		}
 		return;
 	}
-call_handler:
+
 	/* Iff device is idle, reset timeout. */
 	sch = to_subchannel(cdev->dev.parent);
 	if (!stsch(sch->irq, &sch->schib))
@@ -923,8 +923,9 @@ ccw_device_stlck_done(struct ccw_device 
 	case DEV_EVENT_INTERRUPT:
 		irb = (struct irb *) __LC_IRB;
 		/* Check for unsolicited interrupt. */
-		if (irb->scsw.stctl ==
-		    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+		if ((irb->scsw.stctl ==
+		     (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
+		    (!irb->scsw.cc))
 			/* FIXME: we should restart stlck here, but this
 			 * is extremely unlikely ... */
 			goto out_wakeup;
diff -puN drivers/s390/cio/device_id.c~s390-comon-i-o-layer drivers/s390/cio/device_id.c
--- 25/drivers/s390/cio/device_id.c~s390-comon-i-o-layer	2004-06-30 10:16:33.435676840 -0700
+++ 25-akpm/drivers/s390/cio/device_id.c	2004-06-30 10:16:33.458673344 -0700
@@ -303,15 +303,14 @@ ccw_device_sense_id_irq(struct ccw_devic
 
 	sch = to_subchannel(cdev->dev.parent);
 	irb = (struct irb *) __LC_IRB;
-	/*
-	 * Unsolicited interrupts may pertain to an earlier status pending or
-	 * busy condition on the subchannel. Retry sense id.
-	 */
+	/* Retry sense id for cc=1. */
 	if (irb->scsw.stctl ==
 	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		ret = __ccw_device_sense_id_start(cdev);
-		if (ret && ret != -EBUSY)
-			ccw_device_sense_id_done(cdev, ret);
+		if (irb->scsw.cc == 1) {
+			ret = __ccw_device_sense_id_start(cdev);
+			if (ret && ret != -EBUSY)
+				ccw_device_sense_id_done(cdev, ret);
+		}
 		return;
 	}
 	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
diff -puN drivers/s390/cio/device_ops.c~s390-comon-i-o-layer drivers/s390/cio/device_ops.c
--- 25/drivers/s390/cio/device_ops.c~s390-comon-i-o-layer	2004-06-30 10:16:33.437676536 -0700
+++ 25-akpm/drivers/s390/cio/device_ops.c	2004-06-30 10:16:33.459673192 -0700
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.34 $
+ *   $Revision: 1.47 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
diff -puN drivers/s390/cio/device_pgid.c~s390-comon-i-o-layer drivers/s390/cio/device_pgid.c
--- 25/drivers/s390/cio/device_pgid.c~s390-comon-i-o-layer	2004-06-30 10:16:33.438676384 -0700
+++ 25-akpm/drivers/s390/cio/device_pgid.c	2004-06-30 10:16:33.460673040 -0700
@@ -143,15 +143,14 @@ ccw_device_sense_pgid_irq(struct ccw_dev
 	int ret;
 
 	irb = (struct irb *) __LC_IRB;
-	/*
-	 * Unsolicited interrupts may pertain to an earlier status pending or
-	 * busy condition on the subchannel. Retry sense pgid.
-	 */
+	/* Retry sense pgid for cc=1. */
 	if (irb->scsw.stctl ==
 	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		ret = __ccw_device_sense_pgid_start(cdev);
-		if (ret && ret != -EBUSY)
-			ccw_device_sense_pgid_done(cdev, ret);
+		if (irb->scsw.cc == 1) {
+			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)
@@ -310,13 +309,11 @@ ccw_device_verify_irq(struct ccw_device 
 	struct irb *irb;
 
 	irb = (struct irb *) __LC_IRB;
-	/*
-	 * Unsolicited interrupts may pertain to an earlier status pending or
-	 * busy condition on the subchannel. Restart path verification.
-	 */
+	/* Retry set pgid for cc=1. */
 	if (irb->scsw.stctl ==
 	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-		__ccw_device_verify_start(cdev);
+		if (irb->scsw.cc == 1)
+			__ccw_device_verify_start(cdev);
 		return;
 	}
 	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
@@ -397,10 +394,13 @@ ccw_device_disband_irq(struct ccw_device
 	int ret;
 
 	irb = (struct irb *) __LC_IRB;
-	/* Ignore unsolicited interrupts. */
+	/* Retry set pgid for cc=1. */
 	if (irb->scsw.stctl ==
-	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
+		if (irb->scsw.cc == 1)
+			__ccw_device_disband_start(cdev);
 		return;
+	}
 	if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
 		return;
 	sch = to_subchannel(cdev->dev.parent);
diff -puN drivers/s390/cio/device_status.c~s390-comon-i-o-layer drivers/s390/cio/device_status.c
--- 25/drivers/s390/cio/device_status.c~s390-comon-i-o-layer	2004-06-30 10:16:33.439676232 -0700
+++ 25-akpm/drivers/s390/cio/device_status.c	2004-06-30 10:16:33.460673040 -0700
@@ -35,7 +35,7 @@ ccw_device_msg_control_check(struct ccw_
 		return;
 		
 	CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
-		      "received\n"
+		      "received"
 		      " ... device %04X on subchannel %04X, dev_stat "
 		      ": %02X sch_stat : %02X\n",
 		      cdev->private->devno, cdev->private->irq,
@@ -216,8 +216,9 @@ ccw_device_accumulate_irb(struct ccw_dev
 	/*
 	 * Don't accumulate unsolicited interrupts.
 	 */
-	if (irb->scsw.stctl ==
-	    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+	if ((irb->scsw.stctl ==
+	     (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
+	    (!irb->scsw.cc))
 		return;
 
 	cdev_irb = &cdev->private->irb;
diff -puN drivers/s390/cio/Makefile~s390-comon-i-o-layer drivers/s390/cio/Makefile
--- 25/drivers/s390/cio/Makefile~s390-comon-i-o-layer	2004-06-30 10:16:33.441675928 -0700
+++ 25-akpm/drivers/s390/cio/Makefile	2004-06-30 10:16:33.452674256 -0700
@@ -2,7 +2,7 @@
 # Makefile for the S/390 common i/o drivers
 #
 
-obj-y += airq.o blacklist.o chsc.o cio.o css.o requestirq.o 
+obj-y += airq.o blacklist.o chsc.o cio.o css.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
diff -puN drivers/s390/cio/qdio.c~s390-comon-i-o-layer drivers/s390/cio/qdio.c
--- 25/drivers/s390/cio/qdio.c~s390-comon-i-o-layer	2004-06-30 10:16:33.442675776 -0700
+++ 25-akpm/drivers/s390/cio/qdio.c	2004-06-30 10:16:33.463672584 -0700
@@ -56,7 +56,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.80 $"
+#define VERSION_QDIO_C "$Revision: 1.83 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -354,7 +354,8 @@ qdio_stop_polling(struct qdio_q *q)
 		 SLSB_P_INPUT_NOT_INIT);
 	/* 
 	 * we don't issue this SYNC_MEMORY, as we trust Rick T and
-	 * moreover will not use the PROCESSING state, so q->polling was 0
+	 * moreover will not use the PROCESSING state under VM, so
+	 * q->polling was 0 anyway
 	 */
 	/*SYNC_MEMORY;*/
 	if (q->slsb.acc.val[gsf]!=SLSB_P_INPUT_PRIMED)
@@ -732,6 +733,9 @@ qdio_get_inbound_buffer_frontier(struct 
 	volatile char *slsb;
 	int first_not_to_check;
 	char dbf_text[15];
+#ifdef QDIO_USE_PROCESSING_STATE
+	int last_position=-1;
+#endif /* QDIO_USE_PROCESSING_STATE */
 
 	QDIO_DBF_TEXT4(0,trace,"getibfro");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -774,8 +778,14 @@ check_next:
 		if (q->siga_sync) {
 			set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
 		} else {
-			set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_PROCESSING);
+			/* set the previous buffer to NOT_INIT. The current
+			 * buffer will be set to PROCESSING at the end of
+			 * this function to avoid further interrupts. */
+			if (last_position>=0)
+				set_slsb(&slsb[last_position],
+					 SLSB_P_INPUT_NOT_INIT);
 			atomic_set(&q->polling,1);
+			last_position=f_mod_no;
 		}
 #else /* QDIO_USE_PROCESSING_STATE */
 		set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
@@ -814,6 +824,10 @@ check_next:
 		f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
 		atomic_dec(&q->number_of_buffers_used);
 
+#ifdef QDIO_USE_PROCESSING_STATE
+		last_position=-1;
+#endif /* QDIO_USE_PROCESSING_STATE */
+
 		break;
 
 	/* everything else means frontier not changed (HALTED or so) */
@@ -823,6 +837,11 @@ check_next:
 out:
 	q->first_to_check=f_mod_no;
 
+#ifdef QDIO_USE_PROCESSING_STATE
+	if (last_position>=0)
+		set_slsb(&slsb[last_position],SLSB_P_INPUT_PROCESSING);
+#endif /* QDIO_USE_PROCESSING_STATE */
+
 	QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
 
 	return q->first_to_check;
@@ -1160,7 +1179,7 @@ qdio_inbound_processing(struct qdio_q *q
 
 #ifdef QDIO_USE_PROCESSING_STATE
 static inline int
-tiqdio_do_inbound_checks(struct qdio_q *q, int q_laps)
+tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
 {
 	if (!q) {
 		tiqdio_sched_tl();
@@ -1247,7 +1266,7 @@ again:
 	do {
 		int ret;
 
-		ret = tiqdio_do_inbound_checks(q, q_laps);
+		ret = tiqdio_reset_processing_state(q, q_laps);
 		switch (ret) {
 		case 0:
 			return;
@@ -1971,77 +1990,36 @@ out:
 static unsigned int
 tiqdio_check_chsc_availability(void)
 {
-	int result;
 	char dbf_text[15];
 
-	struct {
-		struct chsc_header request;
-		u32 reserved1;
-		u32 reserved2;
-		u32 reserved3;
-		struct chsc_header response;
-		u32 reserved4;
-		u32 general_char[510];
-		u32 chsc_char[518];
-	} *scsc_area;
-		
-	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-	if (!scsc_area) {
-	        QDIO_PRINT_WARN("Was not able to determine available" \
-				"CHSCs due to no memory.\n");
-		return -ENOMEM;
-	}
-
-	scsc_area->request = (struct chsc_header) {
-		.length = 0x0010,
-		.code   = 0x0010,
-	};
-
-	result=chsc(scsc_area);
-	if (result) {
-		QDIO_PRINT_WARN("Was not able to determine " \
-				"available CHSCs, cc=%i.\n",
-				result);
-		result=-EIO;
-		goto exit;
-	}
+	if (!css_characteristics_avail)
+		return -EIO;
 
-	if (scsc_area->response.code != 1) {
-		QDIO_PRINT_WARN("Was not able to determine " \
-				"available CHSCs.\n");
-		result=-EIO;
-		goto exit;
-	}
 	/* Check for bit 41. */
-	if ((scsc_area->general_char[1] & 0x00400000) != 0x00400000) {
+	if (!css_general_characteristics.aif) {
 		QDIO_PRINT_WARN("Adapter interruption facility not " \
 				"installed.\n");
-		result=-ENOENT;
-		goto exit;
+		return -ENOENT;
 	}
 	/* Check for bits 107 and 108. */
-	if ((scsc_area->chsc_char[3] & 0x00180000) != 0x00180000) {
+	if (!css_chsc_characteristics.scssc ||
+	    !css_chsc_characteristics.scsscf) {
 		QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \
 				"not available.\n");
-		result=-ENOENT;
-		goto exit;
+		return -ENOENT;
 	}
 
 	/* Check for OSA/FCP thin interrupts (bit 67). */
-	hydra_thinints = ((scsc_area->general_char[2] & 0x10000000)
-		== 0x10000000);
+	hydra_thinints = css_general_characteristics.aif_osa;
 	sprintf(dbf_text,"hydrati%1x", hydra_thinints);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 
 	/* Check for aif time delay disablement fac (bit 56). If installed,
 	 * omit svs even under lpar (good point by rick again) */
-	omit_svs = ((scsc_area->general_char[1] & 0x00000080)
-		== 0x00000080);
+	omit_svs = css_general_characteristics.aif_tdd;
 	sprintf(dbf_text,"omitsvs%1x", omit_svs);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
-exit:
-	free_page ((unsigned long) scsc_area);
-	return result;
+	return 0;
 }
 
 
diff -puN drivers/s390/cio/qdio.h~s390-comon-i-o-layer drivers/s390/cio/qdio.h
--- 25/drivers/s390/cio/qdio.h~s390-comon-i-o-layer	2004-06-30 10:16:33.444675472 -0700
+++ 25-akpm/drivers/s390/cio/qdio.h	2004-06-30 10:16:33.464672432 -0700
@@ -1,7 +1,7 @@
 #ifndef _CIO_QDIO_H
 #define _CIO_QDIO_H
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.23 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.24 $"
 
 //#define QDIO_DBF_LIKE_HELL
 
@@ -518,6 +518,8 @@ struct qdio_perf_stats {
 struct qdio_q {
 	volatile struct slsb slsb;
 
+	char unused[QDIO_MAX_BUFFERS_PER_Q];
+
 	__u32 * volatile dev_st_chg_ind;
 
 	int is_input_q;
diff -L drivers/s390/cio/requestirq.c -puN drivers/s390/cio/requestirq.c~s390-comon-i-o-layer /dev/null
--- 25/drivers/s390/cio/requestirq.c
+++ /dev/null	2003-09-15 06:40:47.000000000 -0700
@@ -1,45 +0,0 @@
-/*
- *  drivers/s390/cio/requestirq.c
- *   S/390 common I/O routines -- enabling and disabling of devices
- *   $Revision: 1.46 $
- *
- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
- *			      IBM Corporation
- *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
- *		 Arnd Bergmann (arndb@de.ibm.com)
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <asm/lowcore.h>
-
-#include "css.h"
-
-struct pgid global_pgid;
-EXPORT_SYMBOL_GPL(global_pgid);
-
-/*
- * init_IRQ is now only used to set the pgid as early as possible
- */
-void __init
-init_IRQ(void)
-{
-	/*
-	 * Let's build our path group ID here.
-	 */
-	if (MACHINE_NEW_STIDP)
-		global_pgid.cpu_addr = 0x8000;
-	else {
-#ifdef CONFIG_SMP
-		global_pgid.cpu_addr = hard_smp_processor_id();
-#else
-		global_pgid.cpu_addr = 0;
-#endif
-	}
-	global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
-	global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
-	global_pgid.tod_high = (__u32) (get_clock() >> 32);
-}
diff -puN include/asm-s390/setup.h~s390-comon-i-o-layer include/asm-s390/setup.h
--- 25/include/asm-s390/setup.h~s390-comon-i-o-layer	2004-06-30 10:16:33.446675168 -0700
+++ 25-akpm/include/asm-s390/setup.h	2004-06-30 10:16:33.465672280 -0700
@@ -36,7 +36,6 @@ extern unsigned long machine_flags;
 #define MACHINE_IS_P390		(machine_flags & 4)
 #define MACHINE_HAS_MVPG	(machine_flags & 16)
 #define MACHINE_HAS_DIAG44	(machine_flags & 32)
-#define MACHINE_NEW_STIDP	(machine_flags & 64)
 #define MACHINE_HAS_IDTE	(machine_flags & 128)
 
 #ifndef __s390x__
@@ -54,7 +53,7 @@ extern unsigned long machine_flags;
  * Console mode. Override with conmode=
  */
 extern unsigned int console_mode;
-extern unsigned int console_device;
+extern unsigned int console_devno;
 extern unsigned int console_irq;
 
 #define CONSOLE_IS_UNDEFINED	(console_mode == 0)
_
