mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Martin Schwidefsky <schwidefsky@de.ibm.com>
To: torvalds@osdl.org, linux-kernel@vger.kernel.org
Subject: [PATCH] s390 (2/19): common i/o layer.
Date: Thu, 25 Sep 2003 19:15:42 +0200	[thread overview]
Message-ID: <20030925171542.GC2951@mschwid3.boeblingen.de.ibm.com> (raw)

 - Remove initialization of device.name.
 - Don't do put_device after failed get_device in get_ccwdev_by_busid.
 - Fix read_dev_chars and read_conf_data.
 - Call interrupt function of ccw device if path verification has been started.
 - Replace atomic_return_add by atomic_add_return in qdio.
 - Use wait_event instead of homegrown wait loop.
 - Fix reestablish queue problem.
 - Add ungroup attribute to ccw_group devices and add links from each
   ccw device of a group to the group device.
 - Use BUS_ID_SIZE instead of DEVICE_ID_SIZE.
 - Delay path verification if a basic sense is required.
 - Move qdio shutdown code from qdio_free to qdio_shutdown.

diffstat:
 drivers/s390/cio/ccwgroup.c      |  157 ++++++++++++++++-
 drivers/s390/cio/chsc.c          |    6 
 drivers/s390/cio/cio.c           |   18 -
 drivers/s390/cio/css.c           |   17 -
 drivers/s390/cio/css.h           |    1 
 drivers/s390/cio/device.c        |   14 -
 drivers/s390/cio/device.h        |    4 
 drivers/s390/cio/device_fsm.c    |  105 ++---------
 drivers/s390/cio/device_id.c     |    1 
 drivers/s390/cio/device_ops.c    |  214 ++++++++++++++---------
 drivers/s390/cio/device_status.c |   31 ++-
 drivers/s390/cio/qdio.c          |  360 +++++++++++++++++++--------------------
 drivers/s390/cio/qdio.h          |   22 +-
 drivers/s390/net/cu3088.c        |    7 
 include/asm-s390/qdio.h          |    5 
 15 files changed, 540 insertions(+), 422 deletions(-)

diff -urN linux-2.6/drivers/s390/cio/ccwgroup.c linux-2.6-s390/drivers/s390/cio/ccwgroup.c
--- linux-2.6/drivers/s390/cio/ccwgroup.c	Mon Sep  8 21:50:07 2003
+++ linux-2.6-s390/drivers/s390/cio/ccwgroup.c	Thu Sep 25 18:33:22 2003
@@ -1,11 +1,12 @@
 /*
  *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
- *   $Revision: 1.7 $
+ *   $Revision: 1.15 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                       IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -14,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/ctype.h>
+#include <linux/dcache.h>
 
 #include <asm/semaphore.h>
 #include <asm/ccwdev.h>
@@ -56,6 +58,45 @@
 	.hotplug = ccwgroup_hotplug,
 };
 
+static inline void
+__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
+{
+	int i;
+	char str[8];
+
+	for (i = 0; i < gdev->count; i++) {
+		sprintf(str, "cdev%d", i);
+		sysfs_remove_link(&gdev->dev.kobj, str);
+		/* Hack: Make sure we act on still valid subdirs. */
+		if (atomic_read(&gdev->cdev[i]->dev.kobj.dentry->d_count))
+			sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
+					  "group_device");
+	}
+	
+}
+
+/*
+ * Provide an 'ungroup' attribute so the user can remove group devices no
+ * longer needed or accidentially created. Saves memory :)
+ */
+static ssize_t
+ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count)
+{
+	struct ccwgroup_device *gdev;
+
+	gdev = to_ccwgroupdev(dev);
+
+	if (gdev->state != CCWGROUP_OFFLINE)
+		return -EINVAL;
+
+	__ccwgroup_remove_symlinks(gdev);
+	device_unregister(dev);
+
+	return count;
+}
+
+static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
+
 static void
 ccwgroup_release (struct device *dev)
 {
@@ -69,6 +110,40 @@
 	kfree(gdev);
 }
 
+static inline int
+__ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
+{
+	char str[8];
+	int i, rc;
+
+	for (i = 0; i < gdev->count; i++) {
+		rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj, &gdev->dev.kobj,
+				       "group_device");
+		if (rc) {
+			for (--i; i >= 0; i--)
+				sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
+						  "group_device");
+			return rc;
+		}
+	}
+	for (i = 0; i < gdev->count; i++) {
+		sprintf(str, "cdev%d", i);
+		rc = sysfs_create_link(&gdev->dev.kobj, &gdev->cdev[i]->dev.kobj,
+				       str);
+		if (rc) {
+			for (--i; i >= 0; i--) {
+				sprintf(str, "cdev%d", i);
+				sysfs_remove_link(&gdev->dev.kobj, str);
+			}
+			for (i = 0; i < gdev->count; i++)
+				sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
+						  "group_device");
+			return rc;
+		}
+	}
+	return 0;
+}
+
 /*
  * try to add a new ccwgroup device for one driver
  * argc and argv[] are a list of bus_id's of devices
@@ -82,6 +157,7 @@
 {
 	struct ccwgroup_device *gdev;
 	int i;
+	int rc;
 
 	if (argc > 256) /* disallow dumb users */
 		return -EINVAL;
@@ -90,6 +166,8 @@
 	if (!gdev)
 		return -ENOMEM;
 
+	memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0]));
+
 	for (i = 0; i < argc; i++) {
 		gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
 
@@ -97,8 +175,10 @@
 		 * order to be grouped */
 		if (!gdev->cdev[i]
 		    || gdev->cdev[i]->id.driver_info !=
-		       gdev->cdev[0]->id.driver_info)
+		    gdev->cdev[0]->id.driver_info) {
+			rc = -EINVAL;
 			goto error;
+		}
 	}
 
 	*gdev = (struct ccwgroup_device) {
@@ -114,9 +194,24 @@
 	snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
 			gdev->cdev[0]->dev.bus_id);
 
-	/* TODO: make symlinks for sysfs */
-	return device_register(&gdev->dev);
+	rc = device_register(&gdev->dev);
+	
+	if (rc)
+		goto error;
+
+	rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
+
+	if (rc) {
+		device_unregister(&gdev->dev);
+		goto error;
+	}
+
+	rc = __ccwgroup_create_symlinks(gdev);
+	if (!rc)
+		return 0;
 
+	device_remove_file(&gdev->dev, &dev_attr_ungroup);
+	device_unregister(&gdev->dev);
 error:
 	for (i = 0; i < argc; i++)
 		if (gdev->cdev[i])
@@ -124,7 +219,7 @@
 
 	kfree(gdev);
 
-	return -EINVAL;
+	return rc;
 }
 
 static int __init
@@ -213,7 +308,7 @@
 
 	online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE);
 
-	return sprintf(buf, online ? "yes\n" : "no\n");
+	return sprintf(buf, online ? "1\n" : "0\n");
 }
 
 static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
@@ -286,9 +381,59 @@
 	return 0;
 }
 
+static inline struct ccwgroup_device *
+__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
+{
+	struct ccwgroup_device *gdev;
+	struct list_head *entry;
+	struct device *dev;
+	int i, found;
+
+	/*
+	 * Find groupdevice cdev belongs to.
+	 * Unfortunately, we can't use bus_for_each_dev() because of the
+	 * semaphore (and return value of fn() is int).
+	 */
+	if (!get_bus(&ccwgroup_bus_type))
+		return NULL;
+
+	gdev = NULL;
+	down_read(&ccwgroup_bus_type.subsys.rwsem);
+
+	list_for_each(entry, &ccwgroup_bus_type.devices.list) {
+		dev = get_device(container_of(entry, struct device, bus_list));
+		found = 0;
+		if (!dev)
+			continue;
+		gdev = to_ccwgroupdev(dev);
+		for (i = 0; i < gdev->count && (!found); i++) {
+			if (gdev->cdev[i] == cdev)
+				found = 1;
+		}
+		if (found)
+			break;
+		put_device(dev);
+		gdev = NULL;
+	}
+	up_read(&ccwgroup_bus_type.subsys.rwsem);
+	put_bus(&ccwgroup_bus_type);
+
+	return gdev;
+}
+
 int
 ccwgroup_remove_ccwdev(struct ccw_device *cdev)
 {
+	struct ccwgroup_device *gdev;
+
+	/* If one of its devices is gone, the whole group is done for. */
+	gdev = __ccwgroup_get_gdev_by_cdev(cdev);
+	if (gdev) {
+		ccwgroup_set_offline(gdev);
+		__ccwgroup_remove_symlinks(gdev);
+		device_unregister(&gdev->dev);
+		put_device(&gdev->dev);
+	}
 	return 0;
 }
 
diff -urN linux-2.6/drivers/s390/cio/chsc.c linux-2.6-s390/drivers/s390/cio/chsc.c
--- linux-2.6/drivers/s390/cio/chsc.c	Mon Sep  8 21:50:06 2003
+++ linux-2.6-s390/drivers/s390/cio/chsc.c	Thu Sep 25 18:33:22 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.74 $
+ *   $Revision: 1.77 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -865,9 +865,7 @@
 	chp->state = status;
 	chp->dev.parent = &css_bus_device;
 
-	snprintf(chp->dev.name, DEVICE_NAME_SIZE,
-		 "channel path %x", chpid);
-	snprintf(chp->dev.bus_id, DEVICE_ID_SIZE, "chp%x", chpid);
+	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
 
 	/* make it known to the system */
 	ret = device_register(&chp->dev);
diff -urN linux-2.6/drivers/s390/cio/cio.c linux-2.6-s390/drivers/s390/cio/cio.c
--- linux-2.6/drivers/s390/cio/cio.c	Mon Sep  8 21:50:40 2003
+++ linux-2.6-s390/drivers/s390/cio/cio.c	Thu Sep 25 18:33:22 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.100 $
+ *   $Revision: 1.105 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -277,11 +277,6 @@
 	if (!sch)
 		return -ENODEV;
 
-	/*
-	 * we ignore the halt_io() request if ending_status was received but
-	 *  a SENSE operation is waiting for completion.
-	 */
-
 	sprintf (dbf_txt, "haltIO%x", sch->irq);
 	CIO_TRACE_EVENT (2, dbf_txt);
 
@@ -316,10 +311,6 @@
 
 	if (!sch)
 		return -ENODEV;
-	/*
-	 * we ignore the clear_io() request if ending_status was received but
-	 *  a SENSE operation is waiting for completion.
-	 */
 
 	sprintf (dbf_txt, "clearIO%x", sch->irq);
 	CIO_TRACE_EVENT (2, dbf_txt);
@@ -380,7 +371,7 @@
 }
 
 /*
- * Function: cio_cancel
+ * Function: cio_modify
  * Issues a "Modify Subchannel" on the specified subchannel
  */
 static int
@@ -469,11 +460,6 @@
 	sprintf (dbf_txt, "dissch%x", sch->irq);
 	CIO_TRACE_EVENT (2, dbf_txt);
 
-	/*
-	 * If device isn't operational we have to perform delayed
-	 *  disabling when the next interrupt occurs - unless the
-	 *  irq is re-requested prior to the interrupt to occur.
-	 */
 	ccode = stsch (sch->irq, &sch->schib);
 	if (ccode == 3)		/* Not operational. */
 		return -ENODEV;
diff -urN linux-2.6/drivers/s390/cio/css.c linux-2.6-s390/drivers/s390/cio/css.c
--- linux-2.6/drivers/s390/cio/css.c	Mon Sep  8 21:49:53 2003
+++ linux-2.6-s390/drivers/s390/cio/css.c	Thu Sep 25 18:33:22 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.43 $
+ *   $Revision: 1.49 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -27,7 +27,6 @@
 int css_init_done = 0;
 
 struct device css_bus_device = {
-	.name	= "Channel Subsystem 0",
 	.bus_id = "css0",
 };
 
@@ -79,17 +78,6 @@
 static int
 css_register_subchannel(struct subchannel *sch)
 {
-	static const char *subchannel_types[] = {
-		"I/O Subchannel",
-		"CHSC Subchannel",
-		"Message Subchannel",
-		"ADM Subchannel",
-		"undefined subchannel type 4",
-		"undefined subchannel type 5",
-		"undefined subchannel type 6",
-		"undefined subchannel type 7",
-		"undefined subchannel type 8",
-	};
 	int ret;
 
 	/* Initialize the subchannel structure */
@@ -97,8 +85,7 @@
 	sch->dev.bus = &css_bus_type;
 
 	/* Set a name for the subchannel */
-	strlcpy (sch->dev.name, subchannel_types[sch->st], DEVICE_NAME_SIZE);
-	snprintf (sch->dev.bus_id, DEVICE_ID_SIZE, "0:%04x", sch->irq);
+	snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", sch->irq);
 
 	/* make it known to the system */
 	ret = device_register(&sch->dev);
diff -urN linux-2.6/drivers/s390/cio/css.h linux-2.6-s390/drivers/s390/cio/css.h
--- linux-2.6/drivers/s390/cio/css.h	Mon Sep  8 21:51:01 2003
+++ linux-2.6-s390/drivers/s390/cio/css.h	Thu Sep 25 18:33:22 2003
@@ -78,6 +78,7 @@
 		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 */
 	} __attribute__((packed)) flags;
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;
diff -urN linux-2.6/drivers/s390/cio/device.c linux-2.6-s390/drivers/s390/cio/device.c
--- linux-2.6/drivers/s390/cio/device.c	Mon Sep  8 21:50:18 2003
+++ linux-2.6-s390/drivers/s390/cio/device.c	Thu Sep 25 18:33:22 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.60 $
+ *   $Revision: 1.70 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -229,7 +229,7 @@
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
 
-	return sprintf(buf, cdev->online ? "yes\n" : "no\n");
+	return sprintf(buf, cdev->online ? "1\n" : "0\n");
 }
 
 void
@@ -537,8 +537,7 @@
 	init_timer(&cdev->private->timer);
 
 	/* Set an initial name for the device. */
-	snprintf (cdev->dev.name, DEVICE_NAME_SIZE,"ccw device");
-	snprintf (cdev->dev.bus_id, DEVICE_ID_SIZE, "0:%04x",
+	snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x",
 		  sch->schib.pmcw.dev);
 
 	/* Increase counter of devices currently in recognition. */
@@ -679,6 +678,7 @@
 		console_cdev_in_use = 0;
 		return ERR_PTR(ret);
 	}
+	console_cdev.online = 1;
 	return &console_cdev;
 }
 #endif
@@ -702,10 +702,12 @@
 	list_for_each_entry(d, &drv->devices, driver_list) {
 		dev = get_device(d);
 
-		if (dev && !strncmp(bus_id, dev->bus_id, DEVICE_ID_SIZE))
+		if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE))
 			break;
-		else
+		else if (dev) {
 			put_device(dev);
+			dev = NULL;
+		}
 	}
 	up_read(&drv->bus->subsys.rwsem);
 	put_driver(drv);
diff -urN linux-2.6/drivers/s390/cio/device.h linux-2.6-s390/drivers/s390/cio/device.h
--- linux-2.6/drivers/s390/cio/device.h	Mon Sep  8 21:50:21 2003
+++ linux-2.6-s390/drivers/s390/cio/device.h	Thu Sep 25 18:33:22 2003
@@ -15,8 +15,6 @@
 	DEV_STATE_DISBAND_PGID,
 	DEV_STATE_BOXED,
 	/* states to wait for i/o completion before doing something */
-	DEV_STATE_ONLINE_VERIFY,
-	DEV_STATE_W4SENSE_VERIFY,
 	DEV_STATE_CLEAR_VERIFY,
 	DEV_STATE_TIMEOUT_KILL,
 	/* last element! */
@@ -95,7 +93,7 @@
 void ccw_device_disband_irq(struct ccw_device *, enum dev_event);
 void ccw_device_disband_done(struct ccw_device *, int);
 
-void ccw_device_call_handler(struct ccw_device *);
+int ccw_device_call_handler(struct ccw_device *);
 
 void ccw_device_add_stlck(void *);
 int ccw_device_stlck(struct ccw_device *);
diff -urN linux-2.6/drivers/s390/cio/device_fsm.c linux-2.6-s390/drivers/s390/cio/device_fsm.c
--- linux-2.6/drivers/s390/cio/device_fsm.c	Mon Sep  8 21:50:06 2003
+++ linux-2.6-s390/drivers/s390/cio/device_fsm.c	Thu Sep 25 18:33:22 2003
@@ -269,6 +269,7 @@
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
+	cdev->private->flags.doverify = 0;
 	switch (err) {
 	case 0:
 		ccw_device_done(cdev, DEV_STATE_ONLINE);
@@ -419,13 +420,21 @@
 {
 	struct subchannel *sch;
 
-	sch = to_subchannel(cdev->dev.parent);
+	if (!cdev->private->options.pgroup)
+		return;
 	if (cdev->private->state == DEV_STATE_W4SENSE) {
-		cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
+		cdev->private->flags.doverify = 1;
 		return;
 	}
-	if (sch->schib.scsw.actl != 0) {
-		cdev->private->state = DEV_STATE_ONLINE_VERIFY;
+	sch = to_subchannel(cdev->dev.parent);
+	if (sch->schib.scsw.actl != 0 ||
+	    (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
+		/*
+		 * No final status yet or final status not yet delivered
+		 * to the device driver. Can't do path verfication now,
+		 * delay until final status was delivered.
+		 */
+		cdev->private->flags.doverify = 1;
 		return;
 	}
 	/* Device is idle, we can do the path verification. */
@@ -453,19 +462,14 @@
 	ccw_device_accumulate_irb(cdev, irb);
 	if (cdev->private->flags.dosense) {
 		if (ccw_device_do_sense(cdev, irb) == 0) {
-			/* Check if we have to trigger path verification. */
-			if (irb->esw.esw0.erw.pvrf)
-				cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
-			else
-				cdev->private->state = DEV_STATE_W4SENSE;
+			cdev->private->state = DEV_STATE_W4SENSE;
 		}
 		return;
 	}
-	if (irb->esw.esw0.erw.pvrf)
-		/* Try to start path verification. */
+	/* Call the handler. */
+	if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
+		/* Start delayed path verification. */
 		ccw_device_online_verify(cdev, 0);
-	/* No basic sense required, call the handler. */
-	ccw_device_call_handler(cdev);
 }
 
 /*
@@ -485,32 +489,6 @@
 			      ERR_PTR(-ETIMEDOUT));
 }
 
-static void
-ccw_device_irq_verify(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	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 and find out if a basic sense is needed. */
-	ccw_device_accumulate_irb(cdev, irb);
-	if (cdev->private->flags.dosense) {
-		if (ccw_device_do_sense(cdev, irb) == 0)
-			cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
-		return;
-	}
-	/* Try to start delayed device verification. */
-	ccw_device_online_verify(cdev, 0);
-	/* No basic sense required, call the handler. */
-	ccw_device_call_handler(cdev);
-}
-
 /*
  * Got an interrupt for a basic sense.
  */
@@ -530,46 +508,15 @@
 	/* Add basic sense info to irb. */
 	ccw_device_accumulate_basic_sense(cdev, irb);
 	if (cdev->private->flags.dosense) {
-		/* Check if we have to trigger path verification. */
-		if (irb->esw.esw0.erw.pvrf)
-			cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
 		/* Another basic sense is needed. */
 		ccw_device_do_sense(cdev, irb);
 		return;
 	}
 	cdev->private->state = DEV_STATE_ONLINE;
-	if (irb->esw.esw0.erw.pvrf)
-		/* Try to start path verification. */
-		ccw_device_online_verify(cdev, 0);
 	/* Call the handler. */
-	ccw_device_call_handler(cdev);
-}
-
-static void
-ccw_device_w4sense_verify(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	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;
-	}
-	/* Add basic sense info to irb. */
-	ccw_device_accumulate_basic_sense(cdev, irb);
-	if (cdev->private->flags.dosense) {
-		/* Another basic sense is needed. */
-		ccw_device_do_sense(cdev, irb);
-		return;
-	}
-	cdev->private->state = DEV_STATE_ONLINE_VERIFY;
-	/* Start delayed device verification. */
-	ccw_device_online_verify(cdev, 0);
-	/* Call the handler. */
-	ccw_device_call_handler(cdev);
+	if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
+		/* Start delayed path verification. */
+		ccw_device_online_verify(cdev, 0);
 }
 
 static void
@@ -718,18 +665,6 @@
 		[DEV_EVENT_VERIFY]	ccw_device_nop,
 	},
 	/* states to wait for i/o completion before doing something */
-	[DEV_STATE_ONLINE_VERIFY] {
-		[DEV_EVENT_NOTOPER]	ccw_device_online_notoper,
-		[DEV_EVENT_INTERRUPT]	ccw_device_irq_verify,
-		[DEV_EVENT_TIMEOUT]	ccw_device_nop,
-		[DEV_EVENT_VERIFY]	ccw_device_nop,
-	},
-	[DEV_STATE_W4SENSE_VERIFY] {
-		[DEV_EVENT_NOTOPER]	ccw_device_online_notoper,
-		[DEV_EVENT_INTERRUPT]	ccw_device_w4sense_verify,
-		[DEV_EVENT_TIMEOUT]	ccw_device_nop,
-		[DEV_EVENT_VERIFY]	ccw_device_nop,
-	},
 	[DEV_STATE_CLEAR_VERIFY] {
 		[DEV_EVENT_NOTOPER]     ccw_device_online_notoper,
 		[DEV_EVENT_INTERRUPT]   ccw_device_clear_verify,
diff -urN linux-2.6/drivers/s390/cio/device_id.c linux-2.6-s390/drivers/s390/cio/device_id.c
--- linux-2.6/drivers/s390/cio/device_id.c	Mon Sep  8 21:49:50 2003
+++ linux-2.6-s390/drivers/s390/cio/device_id.c	Thu Sep 25 18:33:22 2003
@@ -342,3 +342,4 @@
 	}
 }
 
+EXPORT_SYMBOL(diag210);
diff -urN linux-2.6/drivers/s390/cio/device_ops.c linux-2.6-s390/drivers/s390/cio/device_ops.c
--- linux-2.6/drivers/s390/cio/device_ops.c	Mon Sep  8 21:50:19 2003
+++ linux-2.6-s390/drivers/s390/cio/device_ops.c	Thu Sep 25 18:33:22 2003
@@ -50,9 +50,7 @@
 	if (!cdev)
 		return -ENODEV;
 	if (cdev->private->state != DEV_STATE_ONLINE &&
-	    cdev->private->state != DEV_STATE_W4SENSE &&
-	    cdev->private->state != DEV_STATE_ONLINE_VERIFY &&
-	    cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
+	    cdev->private->state != DEV_STATE_W4SENSE)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
 	if (!sch)
@@ -76,7 +74,8 @@
 	if (!sch)
 		return -ENODEV;
 	if (cdev->private->state != DEV_STATE_ONLINE ||
-	    sch->schib.scsw.actl != 0)
+	    sch->schib.scsw.actl != 0 ||
+	    cdev->private->flags.doverify)
 		return -EBUSY;
 	ret = cio_set_options (sch, flags);
 	if (ret)
@@ -113,9 +112,7 @@
 	if (!cdev)
 		return -ENODEV;
 	if (cdev->private->state != DEV_STATE_ONLINE &&
-	    cdev->private->state != DEV_STATE_W4SENSE &&
-	    cdev->private->state != DEV_STATE_ONLINE_VERIFY &&
-	    cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
+	    cdev->private->state != DEV_STATE_W4SENSE)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
 	if (!sch)
@@ -145,7 +142,7 @@
 /*
  * Pass interrupt to device driver.
  */
-void
+int
 ccw_device_call_handler(struct ccw_device *cdev)
 {
 	struct subchannel *sch;
@@ -167,7 +164,7 @@
 	    !(stctl & SCSW_STCTL_INTER_STATUS) &&
 	    !(cdev->private->options.fast &&
 	      (stctl & SCSW_STCTL_PRIM_STATUS)))
-		return;
+		return 0;
 
 	/*
 	 * Now we are ready to call the device driver interrupt handler.
@@ -180,6 +177,8 @@
 	 * Clear the old and now useless interrupt response block.
 	 */
 	memset(&cdev->private->irb, 0, sizeof(struct irb));
+
+	return 1;
 }
 
 /*
@@ -190,6 +189,8 @@
 {
 	int ciw_cnt;
 
+	if (cdev->private->flags.esid == 0)
+		return NULL;
 	for (ciw_cnt = 0; ciw_cnt < MAX_CIWS; ciw_cnt++)
 		if (cdev->private->senseid.ciw[ciw_cnt].ct == ct)
 			return cdev->private->senseid.ciw + ciw_cnt;
@@ -211,25 +212,89 @@
 static void
 ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
 {
+	if (!ip)
+		/* unsolicited interrupt */
+		return;
+
+	/* Abuse intparm for error reporting. */
+	if (IS_ERR(irb))
+		cdev->private->intparm = -EIO;
+	else if ((irb->scsw.dstat !=
+		  (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
+		 (irb->scsw.cstat != 0)) {
+		/*
+		 * We didn't get channel end / device end. Check if path
+		 * verification has been started; we can retry after it has
+		 * finished. We also retry unit checks except for command reject
+		 * or intervention required.
+		 */
+		 if (cdev->private->flags.doverify ||
+			 cdev->private->state == DEV_STATE_VERIFY)
+			 cdev->private->intparm = -EAGAIN;
+		 if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+		     !(irb->ecw[0] &
+		       (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
+			 cdev->private->intparm = -EAGAIN;
+		 else
+			 cdev->private->intparm = -EIO;
+			 
+	} else
+		cdev->private->intparm = 0;
+	wake_up(&cdev->private->wait_q);
+}
+
+static inline int
+__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic,
+			unsigned long flags)
+{
+	int ret;
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
-	if (!IS_ERR(irb))
-		memcpy(&sch->schib.scsw, &irb->scsw, sizeof(struct scsw));
-	wake_up(&cdev->private->wait_q);
+	do {
+		ret = cio_start (sch, ccw, magic, 0);
+		if ((ret == -EBUSY) || (ret == -EACCES)) {
+			/* Try again later. */
+			schedule_timeout(1);
+			continue;
+		}
+		if (ret != 0)
+			/* Non-retryable error. */
+			break;
+		/* Wait for end of request. */
+		cdev->private->intparm = magic;
+		spin_unlock_irqrestore(&sch->lock, flags);
+		wait_event(cdev->private->wait_q,
+			   (cdev->private->intparm == -EIO) ||
+			   (cdev->private->intparm == -EAGAIN) ||
+			   (cdev->private->intparm == 0));
+		spin_lock_irqsave(&sch->lock, flags);
+		/* Check at least for channel end / device end */
+		if (cdev->private->intparm == -EIO) {
+			/* Non-retryable error. */
+			ret = -EIO;
+			break;
+		}
+		if (cdev->private->intparm == 0)
+			/* Success. */
+			break;
+		/* Try again later. */
+		schedule_timeout(1);
+	} while (1);
+
+	return ret;
 }
 
-/*
- * This routine returns the characteristics for the device
- *  specified. Some old devices might not provide the necessary
- *  command code information during SenseID processing. In this
- *  case the function returns -EINVAL. Otherwise the function
- *  allocates a decice specific data buffer and provides the
- *  device characteristics together with the buffer size. Its
- *  the callers responability to release the kernel memory if
- *  not longer needed. In case of persistent I/O problems -EBUSY
- *  is returned.
- */
+/**
+ * read_dev_chars() - read device characteristics
+ * @param cdev   target ccw device
+ * @param buffer pointer to buffer for rdc data
+ * @param length size of rdc data
+ * @returns 0 for success, negative error value on failure
+ *
+ * Context:
+ *   called for online device, lock not held
+ **/
 int
 read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
 {
@@ -237,13 +302,11 @@
 	char dbf_txt[15];
 	unsigned long flags;
 	struct subchannel *sch;
-	int retry;
 	int ret;
+	struct ccw1 *rdc_ccw;
 
 	if (!cdev)
 		return -ENODEV;
-	if (cdev->private->state != DEV_STATE_ONLINE)
-		return -EINVAL;
 	if (!buffer || !length)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
@@ -251,44 +314,38 @@
 	sprintf (dbf_txt, "rddevch%x", sch->irq);
 	CIO_TRACE_EVENT (4, dbf_txt);
 
-	cdev->private->iccws[0].cmd_code = CCW_CMD_RDC;
-	cdev->private->iccws[0].count = length;
-	cdev->private->iccws[0].flags = CCW_FLAG_SLI;
-	ret = set_normalized_cda (cdev->private->iccws, (*buffer));
-	if (ret != 0)
+	rdc_ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+	if (!rdc_ccw)
+		return -ENOMEM;
+	memset(rdc_ccw, 0, sizeof(struct ccw1));
+	rdc_ccw->cmd_code = CCW_CMD_RDC;
+	rdc_ccw->count = length;
+	rdc_ccw->flags = CCW_FLAG_SLI;
+	ret = set_normalized_cda (rdc_ccw, (*buffer));
+	if (ret != 0) {
+		kfree(rdc_ccw);
 		return ret;
+	}
 
 	spin_lock_irqsave(&sch->lock, flags);
 	/* Save interrupt handler. */
 	handler = cdev->handler;
 	/* Temporarily install own handler. */
 	cdev->handler = ccw_device_wake_up;
-	for (retry = 5; retry > 0; retry--) {
-		/* 0x00524443 == ebcdic "RDC" */
-		ret = cio_start (sch, cdev->private->iccws, 0x00524443, 0);
-		if (ret == -ENODEV)
-			break;
-		if (ret == 0) {
-			/* Wait for end of request. */
-			spin_unlock_irqrestore(&sch->lock, flags);
-			wait_event(cdev->private->wait_q,
-				   sch->schib.scsw.actl == 0);
-			spin_lock_irqsave(&sch->lock, flags);
-			/* Check at least for channel end / device end */
-			if ((sch->schib.scsw.dstat !=
-			     (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-			    (sch->schib.scsw.cstat != 0)) {
-				ret = -EIO;
-				continue;
-			}
-			break;
-		}
-	}
+	if (cdev->private->state != DEV_STATE_ONLINE)
+		ret = -ENODEV;
+	else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify)
+		ret = -EBUSY;
+	else
+		/* 0x00D9C4C3 == ebcdic "RDC" */
+		ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, flags);
+
 	/* Restore interrupt handler. */
 	cdev->handler = handler;
 	spin_unlock_irqrestore(&sch->lock, flags);
 
-	clear_normalized_cda (cdev->private->iccws);
+	clear_normalized_cda (rdc_ccw);
+	kfree(rdc_ccw);
 
 	return ret;
 }
@@ -305,15 +362,11 @@
 	struct ciw *ciw;
 	unsigned long flags;
 	char *rcd_buf;
-	int retry;
 	int ret;
+	struct ccw1 *rcd_ccw;
 
 	if (!cdev)
 		return -ENODEV;
-	if (cdev->private->state != DEV_STATE_ONLINE)
-		return -EINVAL;
-	if (cdev->private->flags.esid == 0)
-		return -EOPNOTSUPP;
 	if (!buffer || !length)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
@@ -328,40 +381,34 @@
 	if (!ciw || ciw->cmd == 0)
 		return -EOPNOTSUPP;
 
+	rcd_ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+	if (!rcd_ccw)
+		return -ENOMEM;
+	memset(rcd_ccw, 0, sizeof(struct ccw1));
 	rcd_buf = kmalloc(ciw->count, GFP_KERNEL | GFP_DMA);
- 	if (!rcd_buf)
+ 	if (!rcd_buf) {
+		kfree(rcd_ccw);
 		return -ENOMEM;
+	}
  	memset (rcd_buf, 0, ciw->count);
-	cdev->private->iccws[0].cmd_code = ciw->cmd;
-	cdev->private->iccws[0].cda = (__u32) __pa (rcd_buf);
-	cdev->private->iccws[0].count = ciw->count;
-	cdev->private->iccws[0].flags = CCW_FLAG_SLI;
+	rcd_ccw->cmd_code = ciw->cmd;
+	rcd_ccw->cda = (__u32) __pa (rcd_buf);
+	rcd_ccw->count = ciw->count;
+	rcd_ccw->flags = CCW_FLAG_SLI;
 
 	spin_lock_irqsave(&sch->lock, flags);
 	/* Save interrupt handler. */
 	handler = cdev->handler;
 	/* Temporarily install own handler. */
 	cdev->handler = ccw_device_wake_up;
-	for (ret = 0, retry = 5; retry > 0; retry--) {
-		/* 0x00524344 == ebcdic "RCD" */
-		ret = cio_start (sch, cdev->private->iccws, 0x00524344, 0);
-		if (ret == -ENODEV)
-			break;
-		if (ret)
-			continue;
-		/* Wait for end of request. */
-		spin_unlock_irqrestore(&sch->lock, flags);
-		wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0);
-		spin_lock_irqsave(&sch->lock, flags);
-		/* Check at least for channel end / device end */
-		if ((sch->schib.scsw.dstat != 
-		     (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-		    (sch->schib.scsw.cstat != 0)) {
-			ret = -EIO;
-			continue;
-		}
-		break;
-	}
+	if (cdev->private->state != DEV_STATE_ONLINE)
+		ret = -ENODEV;
+	else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify)
+		ret = -EBUSY;
+	else
+		/* 0x00D9C3C4 == ebcdic "RCD" */
+		ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, flags);
+
 	/* Restore interrupt handler. */
 	cdev->handler = handler;
 	spin_unlock_irqrestore(&sch->lock, flags);
@@ -377,6 +424,7 @@
 		*length = ciw->count;
 		*buffer = rcd_buf;
 	}
+	kfree(rcd_ccw);
 
 	return ret;
 }
diff -urN linux-2.6/drivers/s390/cio/device_status.c linux-2.6-s390/drivers/s390/cio/device_status.c
--- linux-2.6/drivers/s390/cio/device_status.c	Mon Sep  8 21:50:03 2003
+++ linux-2.6-s390/drivers/s390/cio/device_status.c	Thu Sep 25 18:33:22 2003
@@ -67,7 +67,8 @@
 		      sch->schib.pmcw.pnom);
 
 	sch->lpm &= ~sch->schib.pmcw.pnom;
-	dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+	if (cdev->private->options.pgroup)
+		cdev->private->flags.doverify = 1;
 }
 
 /*
@@ -93,6 +94,21 @@
 }
 
 /*
+ * Check if extended status word is valid.
+ */
+static inline int
+ccw_device_accumulate_esw_valid(struct irb *irb)
+{
+	if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
+		return 0;
+	if (irb->scsw.stctl == 
+	    		(SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
+	    !(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
+		return 0;
+	return 1;
+}
+
+/*
  * Copy valid bits from the extended status word to device irb.
  */
 static inline void
@@ -101,12 +117,7 @@
 	struct irb *cdev_irb;
 	struct sublog *cdev_sublog, *sublog;
 
-	/* Check if extended status word is valid. */
-	if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
-		return;
-	if (irb->scsw.stctl == 
-	    		(SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
-	    !(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
+	if (!ccw_device_accumulate_esw_valid(irb))
 		return;
 
 	cdev_irb = &cdev->private->irb;
@@ -169,6 +180,8 @@
 	cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
 	/* Copy path verification required flag. */
 	cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
+	if (irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
+		cdev->private->flags.doverify = 1;
 	/* Copy concurrent sense bit. */
 	cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
 	if (irb->esw.esw0.erw.cons)
@@ -339,6 +352,10 @@
 		cdev->private->irb.esw.esw0.erw.cons = 1;
 		cdev->private->flags.dosense = 0;
 	}
+	/* Check if path verification is required. */
+	if (ccw_device_accumulate_esw_valid(irb) &&
+	    irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup) 
+		cdev->private->flags.doverify = 1;
 }
 
 /*
diff -urN linux-2.6/drivers/s390/cio/qdio.c linux-2.6-s390/drivers/s390/cio/qdio.c
--- linux-2.6/drivers/s390/cio/qdio.c	Mon Sep  8 21:50:08 2003
+++ linux-2.6-s390/drivers/s390/cio/qdio.c	Thu Sep 25 18:33:22 2003
@@ -55,7 +55,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.55 $"
+#define VERSION_QDIO_C "$Revision: 1.61 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -117,60 +117,6 @@
         asm volatile ("STCK %0" : "=m" (time));
         return time>>12; /* time>>12 is microseconds*/
 }
-static inline unsigned long 
-qdio_get_millis(void)
-{
-	return (unsigned long)(qdio_get_micros()>>12);
-}
-
-static __inline__ int 
-atomic_return_add (int i, atomic_t *v)
-{
-	int old, new;
-	__CS_LOOP(old, new, v, i, "ar");
-	return old;
-}
-
-static void 
-qdio_wait_nonbusy(unsigned int timeout)
-{
-        unsigned int start;
-        char dbf_text[15];
-
-	sprintf(dbf_text,"wtnb%4x",timeout);
-	QDIO_DBF_TEXT3(0,trace,dbf_text);
-
-	start=qdio_get_millis();
-	for (;;) {
-		set_task_state(current,TASK_INTERRUPTIBLE);
-		if (qdio_get_millis()-start>timeout) {
-			goto out;
-		}
-		schedule_timeout(((start+timeout-qdio_get_millis())>>10)*HZ);
-	}
-out:
-	set_task_state(current,TASK_RUNNING);
-}
-
-static int 
-qdio_wait_for_no_use_count(atomic_t *use_count)
-{
-	unsigned long start;
-
-	QDIO_DBF_TEXT3(0,trace,"wtnousec");
-	start=qdio_get_millis();
-	for (;;) {
-		if (qdio_get_millis()-start>QDIO_NO_USE_COUNT_TIMEOUT) {
-			QDIO_DBF_TEXT1(1,trace,"WTNOUSTO");
-			return -ETIME;
-		}
-		if (!atomic_read(use_count)) {
-			QDIO_DBF_TEXT3(0,trace,"wtnoused");
-			return 0;
-		}
-		qdio_wait_nonbusy(QDIO_NO_USE_COUNT_TIME);
-	}
-}
 
 /* 
  * unfortunately, we can't just xchg the values; in do_QDIO we want to reserve
@@ -181,7 +127,7 @@
 static inline int 
 qdio_reserve_q(struct qdio_q *q)
 {
-	return atomic_return_add(1,&q->use_count);
+	return atomic_add_return(1,&q->use_count) - 1;
 }
 
 static inline void 
@@ -1221,21 +1167,18 @@
 qdio_release_irq_memory(struct qdio_irq *irq_ptr)
 {
 	int i;
-	int available;
 
 	for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) {
 		if (!irq_ptr->input_qs[i])
 			goto next;
-		available=0;
 
 		if (irq_ptr->input_qs[i]->slib)
 			kfree(irq_ptr->input_qs[i]->slib);
-			kfree(irq_ptr->input_qs[i]);
+		kfree(irq_ptr->input_qs[i]);
 
 next:
 		if (!irq_ptr->output_qs[i])
 			continue;
-		available=0;
 
 		if (irq_ptr->output_qs[i]->slib)
 			kfree(irq_ptr->output_qs[i]->slib);
@@ -1285,20 +1228,12 @@
 }
 
 static int
-qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
-	      int no_input_qs, int no_output_qs,
-	      qdio_handler_t *input_handler,
-	      qdio_handler_t *output_handler,
-	      unsigned long int_parm,int q_format,
-	      unsigned long flags,
-	      void **inbound_sbals_array,
-	      void **outbound_sbals_array)
+qdio_alloc_qs(struct qdio_irq *irq_ptr,
+	      int no_input_qs, int no_output_qs)
 {
+	int i;
 	struct qdio_q *q;
-	int i,j,result=0;
-	char dbf_text[20]; /* see qdio_initialize */
-	void *ptr;
-	int available;
+	int result=-ENOMEM;
 
 	for (i=0;i<no_input_qs;i++) {
 		q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
@@ -1307,17 +1242,67 @@
 			QDIO_PRINT_ERR("kmalloc of q failed!\n");
 			goto out;
 		}
+
 		memset(q,0,sizeof(struct qdio_q));
 
-		sprintf(dbf_text,"in-q%4x",i);
-		QDIO_DBF_TEXT0(0,setup,dbf_text);
-		QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
+		q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+		if (!q->slib) {
+			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
+			goto out;
+		}
+
+		irq_ptr->input_qs[i]=q;
+	}
+
+	for (i=0;i<no_output_qs;i++) {
+		q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+
+		if (!q) {
+			goto out;
+		}
+
+		memset(q,0,sizeof(struct qdio_q));
 
 		q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
 		if (!q->slib) {
 			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
 			goto out;
 		}
+
+		irq_ptr->output_qs[i]=q;
+	}
+
+	result=0;
+out:
+	return result;
+}
+
+static void
+qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
+       	     int no_input_qs, int no_output_qs,
+	     qdio_handler_t *input_handler,
+	     qdio_handler_t *output_handler,
+	     unsigned long int_parm,int q_format,
+	     unsigned long flags,
+	     void **inbound_sbals_array,
+	     void **outbound_sbals_array)
+{
+	struct qdio_q *q;
+	int i,j;
+	char dbf_text[20]; /* see qdio_initialize */
+	void *ptr;
+	int available;
+
+	sprintf(dbf_text,"qfqs%4x",cdev->private->irq);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	for (i=0;i<no_input_qs;i++) {
+		q=irq_ptr->input_qs[i];
+
+		memset(q,0,((char*)&q->slib)-((char*)q));
+		sprintf(dbf_text,"in-q%4x",i);
+		QDIO_DBF_TEXT0(0,setup,dbf_text);
+		QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
+
 		memset(q->slib,0,PAGE_SIZE);
 		q->sl=(struct sl*)(((char*)q->slib)+PAGE_SIZE/2);
 
@@ -1328,7 +1313,6 @@
 
                 q->queue_type=q_format;
 		q->int_parm=int_parm;
-		irq_ptr->input_qs[i]=q;
 		q->irq=irq_ptr->irq;
 		q->irq_ptr = irq_ptr;
 		q->cdev = cdev;
@@ -1380,22 +1364,13 @@
 	}
 
 	for (i=0;i<no_output_qs;i++) {
-		q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
-
-		if (!q) {
-			goto out;
-		}
-		memset(q,0,sizeof(struct qdio_q));
+		q=irq_ptr->output_qs[i];
+		memset(q,0,((char*)&q->slib)-((char*)q));
 
 		sprintf(dbf_text,"outq%4x",i);
 		QDIO_DBF_TEXT0(0,setup,dbf_text);
 		QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
 
-		q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
-		if (!q->slib) {
-			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
-			goto out;
-		}
 		memset(q->slib,0,PAGE_SIZE);
 		q->sl=(struct sl*)(((char*)q->slib)+PAGE_SIZE/2);
 
@@ -1406,7 +1381,6 @@
 
                 q->queue_type=q_format;
 		q->int_parm=int_parm;
-		irq_ptr->output_qs[i]=q;
 		q->is_input_q=0;
 		q->irq=irq_ptr->irq;
 		q->cdev = cdev;
@@ -1446,10 +1420,6 @@
 /*			q->sbal[j]->element[1].sbalf.i1.key=QDIO_STORAGE_KEY;*/
 		}
 	}
-
-	result=1;
-out:
-	return result;
 }
 
 static void
@@ -1645,7 +1615,6 @@
 	}
 	ccw_device_set_timeout(cdev, 0);
 	wake_up(&cdev->private->wait_q);
-
 }
 
 static void
@@ -1703,7 +1672,6 @@
 
 	switch (irq_ptr->state) {
 	case QDIO_IRQ_STATE_INACTIVE:
-		/* FIXME: defer this past interrupt time */
 		qdio_establish_handle_irq(cdev, cstat, dstat);
 		break;
 
@@ -2128,8 +2096,12 @@
 	for (i=0;i<irq_ptr->no_input_qs;i++) {
 		qdio_unmark_q(irq_ptr->input_qs[i]);
 		tasklet_kill(&irq_ptr->input_qs[i]->tasklet);
-		if (qdio_wait_for_no_use_count(&irq_ptr->input_qs[i]->
-					       use_count))
+		wait_event_interruptible_timeout(cdev->private->wait_q,
+						 !atomic_read(&irq_ptr->
+							      input_qs[i]->
+							      use_count),
+						 QDIO_NO_USE_COUNT_TIMEOUT*HZ);
+		if (atomic_read(&irq_ptr->input_qs[i]->use_count))
 			/*
 			 * FIXME:
 			 * nobody cares about such retval,
@@ -2142,8 +2114,12 @@
 
 	for (i=0;i<irq_ptr->no_output_qs;i++) {
 		tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
-		if (qdio_wait_for_no_use_count(&irq_ptr->output_qs[i]->
-					       use_count))
+		wait_event_interruptible_timeout(cdev->private->wait_q,
+						 !atomic_read(&irq_ptr->
+							      output_qs[i]->
+							      use_count),
+						 QDIO_NO_USE_COUNT_TIMEOUT*HZ);
+		if (atomic_read(&irq_ptr->output_qs[i]->use_count))
 			/*
 			 * FIXME:
 			 * nobody cares about such retval,
@@ -2176,16 +2152,7 @@
 	wait_event(cdev->private->wait_q,
 		   irq_ptr->state == QDIO_IRQ_STATE_INACTIVE ||
 		   irq_ptr->state == QDIO_IRQ_STATE_ERR);
-	/* Ignore errors. */
-	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
-out:
-	up(&irq_ptr->setting_up_sema);
-	return result;
-}
 
-static inline void
-qdio_cleanup_finish(struct ccw_device *cdev, struct qdio_irq *irq_ptr)
-{
 	if (irq_ptr->is_thinint_irq) {
 		qdio_put_indicator((__u32*)irq_ptr->dev_st_chg_ind);
 		tiqdio_set_subchannel_ind(irq_ptr,1); 
@@ -2196,8 +2163,12 @@
  	if ((void*)cdev->handler == (void*)qdio_handler)
  		cdev->handler=irq_ptr->original_int_handler;
 
-	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
-
+	/* Ignore errors. */
+	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
+	ccw_device_set_timeout(cdev, 0);
+out:
+	up(&irq_ptr->setting_up_sema);
+	return result;
 }
 
 int
@@ -2216,10 +2187,6 @@
 	QDIO_DBF_TEXT1(0,trace,dbf_text);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 
-	if (cdev->private->state != DEV_STATE_ONLINE)
-		return -EINVAL;
-
-	qdio_cleanup_finish(cdev, irq_ptr);
 	cdev->private->qdio_data = 0;
 
 	up(&irq_ptr->setting_up_sema);
@@ -2234,9 +2201,6 @@
 {
 	char dbf_text[20]; /* if a printf would print out more than 8 chars */
 
-	sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
-	QDIO_DBF_TEXT0(0,setup,dbf_text);
-	QDIO_DBF_TEXT0(0,trace,dbf_text);
 	sprintf(dbf_text,"qfmt:%x",init_data->q_format);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 	QDIO_DBF_TEXT0(0,setup,init_data->adapter_name);
@@ -2409,6 +2373,8 @@
 	struct qdio_irq *irq_ptr;
 	char dbf_text[15];
 
+	irq_ptr = cdev->private->qdio_data;
+
 	sprintf(dbf_text,"qehi%4x",cdev->private->irq);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 	QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -2418,28 +2384,6 @@
 		return;
 	}
 
-	irq_ptr = cdev->private->qdio_data;
-
-	if (MACHINE_IS_VM)
-		irq_ptr->qdioac=qdio_check_siga_needs(irq_ptr->irq);
-	else
-                irq_ptr->qdioac=CHSC_FLAG_SIGA_INPUT_NECESSARY
-                        | CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
-
-	sprintf(dbf_text,"qdioac%2x",irq_ptr->qdioac);
-	QDIO_DBF_TEXT2(0,setup,dbf_text);
-
-	sprintf(dbf_text,"qib ac%2x",irq_ptr->qib.ac);
-	QDIO_DBF_TEXT2(0,setup,dbf_text);
-
-	irq_ptr->hydra_gives_outbound_pcis=
-		irq_ptr->qib.ac&QIB_AC_OUTBOUND_PCI_SUPPORTED;
-	irq_ptr->sync_done_on_outb_pcis=
-		irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS;
-
-	qdio_initialize_set_siga_flags_input(irq_ptr);
-	qdio_initialize_set_siga_flags_output(irq_ptr);
-
 	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED);
 	ccw_device_set_timeout(cdev, 0);
 }
@@ -2456,7 +2400,7 @@
 
 	rc = qdio_allocate(init_data);
 	if (rc == 0) {
-		rc = qdio_establish(init_data->cdev);
+		rc = qdio_establish(init_data);
 		if (rc != 0)
 			qdio_free(init_data->cdev);
 	}
@@ -2468,13 +2412,12 @@
 int
 qdio_allocate(struct qdio_initialize *init_data)
 {
-	int i;
 	struct qdio_irq *irq_ptr;
-	struct ciw *ciw;
-	int result;
-	int is_iqdio;
 	char dbf_text[15];
 
+	sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_TEXT0(0,trace,dbf_text);
 	if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
 	     (init_data->no_output_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
 	     ((init_data->no_input_qs) && (!init_data->input_handler)) ||
@@ -2501,7 +2444,8 @@
 	}
 
 	memset(irq_ptr,0,sizeof(struct qdio_irq));
-        /* wipes qib.ac, required by ar7063 */
+
+	init_MUTEX(&irq_ptr->setting_up_sema);
 
 	irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
   	if (!(irq_ptr->qdr)) {
@@ -2510,10 +2454,38 @@
     		QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
 		return -ENOMEM;
        	}
-	memset(irq_ptr->qdr,0,sizeof(struct qdr));
 	QDIO_DBF_TEXT0(0,setup,"qdr:");
 	QDIO_DBF_HEX0(0,setup,&irq_ptr->qdr,sizeof(void*));
 
+	if (qdio_alloc_qs(irq_ptr,
+       			  init_data->no_input_qs,
+			  init_data->no_output_qs)) {
+		qdio_release_irq_memory(irq_ptr);
+		return -ENOMEM;
+	}
+
+	init_data->cdev->private->qdio_data = irq_ptr;
+
+	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
+
+	return 0;
+}
+
+int qdio_fill_irq(struct qdio_initialize *init_data)
+{
+	int i;
+	char dbf_text[15];
+	struct ciw *ciw;
+	int is_iqdio;
+	struct qdio_irq *irq_ptr;
+
+	irq_ptr = init_data->cdev->private->qdio_data;
+
+	memset(irq_ptr,0,((char*)&irq_ptr->qdr)-((char*)irq_ptr));
+
+        /* wipes qib.ac, required by ar7063 */
+	memset(irq_ptr->qdr,0,sizeof(struct qdr));
+
 	irq_ptr->int_parm=init_data->int_parm;
 
 	irq_ptr->irq = init_data->cdev->private->irq;
@@ -2548,19 +2520,14 @@
 	irq_ptr->aqueue.cmd=DEFAULT_ACTIVATE_QS_CMD;
 	irq_ptr->aqueue.count=DEFAULT_ACTIVATE_QS_COUNT;
 
-	if (!qdio_alloc_qs(irq_ptr, init_data->cdev,
-			   init_data->no_input_qs,
-			   init_data->no_output_qs,
-			   init_data->input_handler,
-			   init_data->output_handler,init_data->int_parm,
-			   init_data->q_format,init_data->flags,
-			   init_data->input_sbal_addr_array,
-			   init_data->output_sbal_addr_array)) {
-		qdio_release_irq_memory(irq_ptr);
-		return -ENOMEM;
-	}
-
-	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
+	qdio_fill_qs(irq_ptr, init_data->cdev,
+		     init_data->no_input_qs,
+		     init_data->no_output_qs,
+		     init_data->input_handler,
+		     init_data->output_handler,init_data->int_parm,
+		     init_data->q_format,init_data->flags,
+	   	     init_data->input_sbal_addr_array,
+   		     init_data->output_sbal_addr_array);
 
 	if (!try_module_get(THIS_MODULE)) {
 		QDIO_PRINT_CRIT("try_module_get() failed!\n");
@@ -2568,10 +2535,6 @@
 		return -EINVAL;
 	}
 
-	init_MUTEX_LOCKED(&irq_ptr->setting_up_sema);
-
-	init_data->cdev->private->qdio_data = irq_ptr;
-
 	qdio_fill_thresholds(irq_ptr,init_data->no_input_qs,
 			     init_data->no_output_qs,
 			     init_data->min_input_threshold,
@@ -2636,31 +2599,21 @@
 	irq_ptr->original_int_handler = init_data->cdev->handler;
 	init_data->cdev->handler = qdio_handler;
 
-	/* the thinint CHSC stuff */
-	if (irq_ptr->is_thinint_irq) {
-
-		result = tiqdio_set_subchannel_ind(irq_ptr,0);
-		if (result) {
-			up(&irq_ptr->setting_up_sema);
-			qdio_cleanup(init_data->cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
-			return result;
-		}
-		tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
-	}
-
 	up(&irq_ptr->setting_up_sema);
 
 	return 0;
 }
 
 int
-qdio_establish(struct ccw_device *cdev)
+qdio_establish(struct qdio_initialize *init_data)
 {
 	struct qdio_irq *irq_ptr;
 	unsigned long saveflags;
 	int result, result2;
+	struct ccw_device *cdev;
 	char dbf_text[20];
 
+	cdev=init_data->cdev;
 	irq_ptr = cdev->private->qdio_data;
 	if (!irq_ptr)
 		return -EINVAL;
@@ -2670,6 +2623,20 @@
 	
 	down(&irq_ptr->setting_up_sema);
 
+	qdio_fill_irq(init_data);
+
+	/* the thinint CHSC stuff */
+	if (irq_ptr->is_thinint_irq) {
+
+		result = tiqdio_set_subchannel_ind(irq_ptr,0);
+		if (result) {
+			up(&irq_ptr->setting_up_sema);
+			qdio_cleanup(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
+			return result;
+		}
+		tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
+	}
+
 	sprintf(dbf_text,"qest%4x",cdev->private->irq);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 	QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -2724,6 +2691,26 @@
 		result = -EIO;
 	}
 
+	if (MACHINE_IS_VM)
+		irq_ptr->qdioac=qdio_check_siga_needs(irq_ptr->irq);
+	else
+                irq_ptr->qdioac=CHSC_FLAG_SIGA_INPUT_NECESSARY
+                        | CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
+
+	sprintf(dbf_text,"qdioac%2x",irq_ptr->qdioac);
+	QDIO_DBF_TEXT2(0,setup,dbf_text);
+
+	sprintf(dbf_text,"qib ac%2x",irq_ptr->qib.ac);
+	QDIO_DBF_TEXT2(0,setup,dbf_text);
+
+	irq_ptr->hydra_gives_outbound_pcis=
+		irq_ptr->qib.ac&QIB_AC_OUTBOUND_PCI_SUPPORTED;
+	irq_ptr->sync_done_on_outb_pcis=
+		irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS;
+
+	qdio_initialize_set_siga_flags_input(irq_ptr);
+	qdio_initialize_set_siga_flags_output(irq_ptr);
+
 	up(&irq_ptr->setting_up_sema);
 
 	return result;
@@ -2806,10 +2793,23 @@
 		}
 	}
 
-	qdio_wait_nonbusy(QDIO_ACTIVATE_TIMEOUT);
-
-	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
+	wait_event_interruptible_timeout(cdev->private->wait_q,
+					 ((irq_ptr->state ==
+					  QDIO_IRQ_STATE_STOPPED) ||
+					  (irq_ptr->state ==
+					   QDIO_IRQ_STATE_ERR)),
+					 (QDIO_ACTIVATE_TIMEOUT>>10)*HZ);
 
+	switch (irq_ptr->state) {
+	case QDIO_IRQ_STATE_STOPPED:
+	case QDIO_IRQ_STATE_ERR:
+		qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
+		result = -EIO;
+		break;
+	default:
+		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
+		result = 0;
+	}
  out:
 	up(&irq_ptr->setting_up_sema);
 
@@ -2855,7 +2855,7 @@
 	int used_elements;
 
         /* This is the inbound handling of queues */
-	used_elements=atomic_return_add(count, &q->number_of_buffers_used);
+	used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
 	
 	qdio_do_qdio_fill_input(q,qidx,count,buffers);
 	
@@ -2897,7 +2897,7 @@
 
 	qdio_do_qdio_fill_output(q,qidx,count,buffers);
 
-	used_elements=atomic_return_add(count, &q->number_of_buffers_used);
+	used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
 
 	if (callflags&QDIO_FLAG_DONT_SIGA) {
 #ifdef QDIO_PERFORMANCE_STATS
diff -urN linux-2.6/drivers/s390/cio/qdio.h linux-2.6-s390/drivers/s390/cio/qdio.h
--- linux-2.6/drivers/s390/cio/qdio.h	Mon Sep  8 21:49:57 2003
+++ linux-2.6-s390/drivers/s390/cio/qdio.h	Thu Sep 25 18:33:22 2003
@@ -1,7 +1,7 @@
 #ifndef _CIO_QDIO_H
 #define _CIO_QDIO_H
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.18 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.20 $"
 
 //#define QDIO_DBF_LIKE_HELL
 
@@ -56,7 +56,6 @@
 #define QDIO_STATS_CLASSES 2
 #define QDIO_STATS_COUNT_NEEDED 2*/
 
-#define QDIO_NO_USE_COUNT_TIME 10
 #define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
 					  exiting without having use_count
 					  of the queue to 0 */
@@ -577,9 +576,6 @@
 	volatile struct qdio_q *list_next;
 	volatile struct qdio_q *list_prev;
 
-	struct slib *slib; /* a page is allocated under this pointer,
-			      sl points into this page, offset PAGE_SIZE/2
-			      (after slib) */
 	struct sl *sl;
 	volatile struct sbal *sbal[QDIO_MAX_BUFFERS_PER_Q];
 
@@ -605,6 +601,11 @@
 		__u64 last_transfer_time;
 	} timing;
         unsigned int queue_type;
+
+	/* leave this member at the end. won't be cleared in qdio_fill_qs */
+	struct slib *slib; /* a page is allocated under this pointer,
+			      sl points into this page, offset PAGE_SIZE/2
+			      (after slib) */
 } __attribute__ ((aligned(256)));
 
 struct qdio_irq {
@@ -619,20 +620,14 @@
 	unsigned int sync_done_on_outb_pcis;
 
 	enum qdio_irq_states state;
-	struct semaphore setting_up_sema;
 
 	unsigned int no_input_qs;
 	unsigned int no_output_qs;
 
 	unsigned char qdioac;
 
-	struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
-	struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
-
 	struct ccw1 ccw;
 
-	struct qdr *qdr;
-
 	struct ciw equeue;
 	struct ciw aqueue;
 
@@ -641,5 +636,10 @@
  	void (*original_int_handler) (struct ccw_device *,
  				      unsigned long, struct irb *);
 
+	/* leave these four members together at the end. won't be cleared in qdio_fill_irq */
+	struct qdr *qdr;
+	struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
+	struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
+	struct semaphore setting_up_sema;
 };
 #endif
diff -urN linux-2.6/drivers/s390/net/cu3088.c linux-2.6-s390/drivers/s390/net/cu3088.c
--- linux-2.6/drivers/s390/net/cu3088.c	Mon Sep  8 21:50:00 2003
+++ linux-2.6-s390/drivers/s390/net/cu3088.c	Thu Sep 25 18:33:22 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: cu3088.c,v 1.26 2003/01/17 13:46:13 cohuck Exp $
+ * $Id: cu3088.c,v 1.30 2003/08/28 11:14:11 cohuck Exp $
  *
  * CTC / LCS ccw_device driver
  *
@@ -56,7 +56,6 @@
 static struct ccw_driver cu3088_driver;
 
 struct device cu3088_root_dev = {
-	.name   = "CU3088 Devices",
 	.bus_id = "cu3088",
 };
 
@@ -64,7 +63,7 @@
 group_write(struct device_driver *drv, const char *buf, size_t count)
 {
 	const char *start, *end;
-	char bus_ids[2][BUS_ID_SIZE+1], *argv[2];
+	char bus_ids[2][BUS_ID_SIZE], *argv[2];
 	int i;
 	int ret;
 	struct ccwgroup_driver *cdrv;
@@ -79,7 +78,7 @@
 
 		if (!(end = strchr(start, delim[i])))
 			return count;
-		len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start)+1;
+		len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
 		strlcpy (bus_ids[i], start, len);
 		argv[i] = bus_ids[i];
 		start = end + 1;
diff -urN linux-2.6/include/asm-s390/qdio.h linux-2.6-s390/include/asm-s390/qdio.h
--- linux-2.6/include/asm-s390/qdio.h	Mon Sep  8 21:49:55 2003
+++ linux-2.6-s390/include/asm-s390/qdio.h	Thu Sep 25 18:33:22 2003
@@ -76,7 +76,7 @@
 #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01
 #define QDIO_FLAG_CLEANUP_USING_HALT 0x02
 
-struct qdio_initialize{
+struct qdio_initialize {
 	struct ccw_device *cdev;
 	unsigned char q_format;
 	unsigned char adapter_name[8];
@@ -99,9 +99,10 @@
 	void **input_sbal_addr_array; /* addr of n*128 void ptrs */
 	void **output_sbal_addr_array; /* addr of n*128 void ptrs */
 };
+
 extern int qdio_initialize(struct qdio_initialize *init_data);
 extern int qdio_allocate(struct qdio_initialize *init_data);
-extern int qdio_establish(struct ccw_device *);
+extern int qdio_establish(struct qdio_initialize *init_data);
 
 extern int qdio_activate(struct ccw_device *,int flags);
 

             reply	other threads:[~2003-09-25 17:19 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-09-25 17:15 Martin Schwidefsky [this message]
2003-09-26  8:02 ` Christoph Hellwig
2003-09-26  9:36 Martin Schwidefsky
2003-09-29  8:24 Martin Schwidefsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030925171542.GC2951@mschwid3.boeblingen.de.ibm.com \
    --to=schwidefsky@de.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®