patch-2.4.22 linux-2.4.22/drivers/s390/block/dasd.c

Next file: linux-2.4.22/drivers/s390/block/dasd_3990_erp.c
Previous file: linux-2.4.22/drivers/s390/Config.in
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/s390/block/dasd.c linux-2.4.22/drivers/s390/block/dasd.c
@@ -6,6 +6,8 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
+ * $Revision: 1.289 $
+ *
  * History of changes (starts July 2000)
  * 11/09/00 complete redesign after code review
  * 02/01/01 added dynamic registration of ioctls
@@ -33,6 +35,7 @@
  * 06/26/01 hopefully fixed PL030172SBA,PL030234SBA
  * 07/09/01 fixed PL030324MSH (wrong statistics output)
  * 07/16/01 merged in new fixes for handling low-mem situations
+ * 01/22/01 fixed PL030579KBE (wrong statistics)
  */
 
 #include <linux/config.h>
@@ -70,7 +73,6 @@
 #include <asm/s390_ext.h>
 #include <asm/s390dyn.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
 
 #include "dasd_int.h"
 
@@ -84,8 +86,9 @@
 #include "dasd_diag.h"
 #endif				/*  CONFIG_DASD_DIAG */
 
-/* SECTION: exported variables of dasd.c */
-
+/********************************************************************************
+ * SECTION: exported variables of dasd.c 
+ ********************************************************************************/
 debug_info_t *dasd_debug_area;
 
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
@@ -94,6 +97,9 @@
 MODULE_SUPPORTED_DEVICE ("dasd");
 MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s");
 MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
+MODULE_LICENSE ("GPL");
+#endif
 EXPORT_SYMBOL (dasd_chanq_enq_head);
 EXPORT_SYMBOL (dasd_debug_area);
 EXPORT_SYMBOL (dasd_chanq_enq);
@@ -103,6 +109,7 @@
 EXPORT_SYMBOL (dasd_start_IO);
 EXPORT_SYMBOL (dasd_term_IO);
 EXPORT_SYMBOL (dasd_schedule_bh);
+EXPORT_SYMBOL (dasd_schedule_bh_timed);
 EXPORT_SYMBOL (dasd_int_handler);
 EXPORT_SYMBOL (dasd_oper_handler);
 EXPORT_SYMBOL (dasd_alloc_request);
@@ -115,17 +122,24 @@
 EXPORT_SYMBOL (dasd_set_normalized_cda);
 EXPORT_SYMBOL (dasd_device_from_kdev);
 
-/* SECTION: Constant definitions to be used within this file */
+
+/********************************************************************************
+ * SECTION: Constant definitions to be used within this file 
+ ********************************************************************************/
 
 #define PRINTK_HEADER DASD_NAME":"
-#undef  DASD_PROFILE            /* fill profile information - used for */
+#define DASD_PROFILE            /* fill profile information - used for */
                                 /* statistics and perfomance           */
 
-#define DASD_MIN_SIZE_FOR_QUEUE 32
-#undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
-#define DASD_CHANQ_MAX_SIZE 6
-
-/* SECTION: prototypes for static functions of dasd.c */
+#ifndef CONFIG_PROC_FS          /* DASD_PROFILE doesn't make sense     */
+#undef DASD_PROFILE             /* without procfs                      */
+#endif /* not CONFIG_PROC_FS */
+
+#define DASD_CHANQ_MAX_SIZE 4
+
+/********************************************************************************
+ * SECTION: prototypes for static functions of dasd.c 
+ ********************************************************************************/
 
 static request_fn_proc do_dasd_request;
 static int dasd_set_device_level (unsigned int, dasd_discipline_t *, int);
@@ -147,7 +161,11 @@
 static struct block_device_operations dasd_device_operations;
 static inline dasd_device_t ** dasd_device_from_devno (int);
 static void dasd_process_queues (dasd_device_t * device);
-/* SECTION: static variables of dasd.c */
+static int  dasd_sleep_on_immediate (ccw_req_t *cqr);
+
+/********************************************************************************
+ * SECTION: static variables of dasd.c 
+ ********************************************************************************/
 
 static devfs_handle_t dasd_devfs_handle;
 static wait_queue_head_t dasd_init_waitq;
@@ -155,7 +173,9 @@
 
 #ifdef CONFIG_DASD_DYNAMIC
 
-/* SECTION: managing dynamic configuration of dasd_driver */
+/********************************************************************************
+ * SECTION: managing dynamic configuration of dasd_driver 
+ ********************************************************************************/
 
 static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head);
 
@@ -188,15 +208,17 @@
 
 #endif				/* CONFIG_DASD_DYNAMIC */
 
-/* SECTION: managing setup of dasd_driver */
+/********************************************************************************
+ * SECTION: managing setup of dasd_driver 
+ ********************************************************************************/
 
 /* default setting is probeonly, autodetect */
-static int dasd_probeonly = 1;	/* is true, when probeonly mode is active */
-static int dasd_autodetect = 1;	/* is true, when autodetection is active */
+static int dasd_probeonly =  0;	/* is true, when probeonly mode is active */
+static int dasd_autodetect = 0;	/* is true, when autodetection is active */
 
 static dasd_range_t dasd_range_head =
     { list:LIST_HEAD_INIT (dasd_range_head.list) };
-static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t range_lock     = SPIN_LOCK_UNLOCKED;
 
 /*
  * function: dasd_create_range
@@ -210,20 +232,24 @@
         int i;
 
 	if ( from > to ) {
-                printk (KERN_WARNING PRINTK_HEADER 
-                        "Adding device range %04x-%04x: range invalid, ignoring.\n",
-                        from,
-                        to);
+
+                MESSAGE (KERN_WARNING, 
+                         "Adding device range %04x-%04x: "
+                         "range invalid, ignoring.",
+                         from,
+                         to);
 
 		return NULL;
 	}
 	for (i=from;i<=to;i++) {
                 if (dasd_device_from_devno(i)) {
-                        printk (KERN_WARNING PRINTK_HEADER 
-                                "device range %04x-%04x: device %04x is already in a range.\n",
-                                from,
-                                to,
-                                i);
+
+                        MESSAGE (KERN_WARNING,
+                                 "device range %04x-%04x: device "
+                                 "%04x is already in a range.",
+                                 from,
+                                 to,
+                                 i);
                 }
         }
 	range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL);
@@ -392,7 +418,9 @@
 	return -ENODEV;
 }
 
-/* SECTION: parsing the dasd= parameter of the parmline/insmod cmdline */
+/********************************************************************************
+ * SECTION: parsing the dasd= parameter of the parmline/insmod cmdline 
+ ********************************************************************************/
 
 /*
  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
@@ -426,11 +454,14 @@
 			*end = '\0';
 			end++;
 		}
-		dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
+		dasd[count] = kmalloc (len * sizeof (char), 
+                                       GFP_ATOMIC);
 		if (dasd[count] == NULL) {
-			printk (KERN_WARNING PRINTK_HEADER
-				"can't store dasd= parameter no %d\n",
-				count + 1);
+
+			MESSAGE (KERN_WARNING,
+                                 "can't store dasd= parameter no"
+                                 " %d",
+                                 count + 1);
 			break;
 		}
 		memset (dasd[count], 0, len * sizeof (char));
@@ -500,10 +531,13 @@
         int val,i,start;
 
         buffer=(char*)kmalloc((strlen(str)+1)*sizeof(char),GFP_ATOMIC);
+
         if (buffer==NULL) {
-            printk (KERN_WARNING PRINTK_HEADER
-                    "can't parse dasd= parameter %s due to low memory\n",
-                    str);
+
+                MESSAGE (KERN_WARNING,
+                         "can't parse dasd= parameter %s due "
+                         "to low memory",
+                         str);
         }
 
         /* remove leading '0x' */
@@ -528,7 +562,7 @@
         val = simple_strtoul (buffer, &buffer, 16);
 
         /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */
-        *features = DASD_DEFAULT_FEATURES;
+        *features = DASD_FEATURE_DEFAULT;
 
         if (temp[i]=='(') {
 
@@ -545,14 +579,18 @@
                                         (*features) |= DASD_FEATURE_READONLY;
                                         break;
                                 }
-                                printk (KERN_WARNING PRINTK_HEADER 
-                                        "unsupported feature: %s, ignoring setting",
-                                        buffer);
+
+                                MESSAGE (KERN_WARNING,
+                                         "unsupported feature: %s, "
+                                         "ignoring setting",
+                                         buffer);
                         }
                 }
         }
 
         *stra = temp+i;
+        if ((val > 65535) || (val < 0))
+                return -EINVAL;
         return val;
 }
 
@@ -569,22 +607,23 @@
         int features;
         int rc = 0;
 
-	if (*str) {
-		/* turn off probeonly mode, if any dasd parameter is present */
-		dasd_probeonly = 0;
-		dasd_autodetect = 0;
-	}
 	while (*str) {
 		temp = *str;
 		from = 0;
 		to = 0;
 		if (strcmp ("autodetect", *str) == 0) {
 			dasd_autodetect = 1;
-			printk (KERN_INFO "turning to autodetection mode\n");
+
+			MESSAGE (KERN_INFO, "%s",
+                                 "turning to autodetection mode");
+
 			break;
 		} else if (strcmp ("probeonly", *str) == 0) {
 			dasd_probeonly = 1;
-			printk (KERN_INFO "turning to probeonly mode\n");
+
+			MESSAGE (KERN_INFO, "%s",
+                                 "turning to probeonly mode");
+
 			break;
 		} else {
 			/* turn off autodetect mode, if any range is present */
@@ -609,20 +648,16 @@
         return rc;
 }
 
-/* SECTION: Dealing with devices registered to multiple major numbers */
+/********************************************************************************
+ * SECTION: Dealing with devices registered to multiple major numbers 
+ ********************************************************************************/
 
 static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
 
-static major_info_t dasd_major_info[] = {
-	{
-	      list:LIST_HEAD_INIT (dasd_major_info[1].list)
-	 },
-	{
-	      list:LIST_HEAD_INIT (dasd_major_info[0].list),
-	      gendisk:{
-	  INIT_GENDISK (94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR)
-	  },
-      flags:DASD_MAJOR_INFO_IS_STATIC}
+static struct list_head dasd_major_info = LIST_HEAD_INIT(dasd_major_info);
+static major_info_t dasd_major_static = {
+        gendisk:{INIT_GENDISK(94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR)},
+        flags: DASD_MAJOR_INFO_IS_STATIC
 };
 
 static major_info_t *
@@ -658,8 +693,11 @@
 	if (major_info == NULL) {
 		major_info = get_new_major_info ();
 		if (!major_info) {
-			printk (KERN_WARNING PRINTK_HEADER
-				"Cannot get memory to allocate another major number\n");
+
+			MESSAGE (KERN_WARNING, "%s",
+				"Cannot get memory to allocate another "
+                                 "major number");
+
 			return -ENOMEM;
 		}
 	}
@@ -686,10 +724,12 @@
         /* register blockdevice */
 	rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
 	if (rc < 0) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Cannot register to major no %d, rc = %d\n",
-                        major, 
-                        rc);
+                
+		MESSAGE (KERN_WARNING,
+                         "Cannot register to major no %d, rc = %d",
+                         major, 
+                         rc);
+
 		goto out_reg_blkdev; 
 	} else {
 		major_info->flags |= DASD_MAJOR_INFO_REGISTERED;
@@ -698,7 +738,7 @@
 	/* Insert the new major info into dasd_major_info if needed (dynamic major) */
 	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
 		spin_lock_irqsave (&dasd_major_lock, flags);
-		list_add_tail (&major_info->list, &dasd_major_info[0].list);
+		list_add_tail (&major_info->list, &dasd_major_info);
 		spin_unlock_irqrestore (&dasd_major_lock, flags);
 	}
 
@@ -791,10 +831,11 @@
         /* unregister blockdevice */
 	rc = devfs_unregister_blkdev (major, DASD_NAME);
 	if (rc < 0) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Unable to unregister from major no %d, rc = %d\n", 
-                        major,
-			rc);
+
+		MESSAGE (KERN_WARNING,
+                         "Unable to unregister from major no %d, rc = %d", 
+                         major,
+                         rc);
 	} else {
 		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
 	}
@@ -844,10 +885,12 @@
 
 	rc = devfs_unregister_blkdev (major, DASD_NAME);
 	if (rc < 0) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Cannot unregister from major no %d, rc = %d\n",
-                        major,
-			rc);
+
+		MESSAGE (KERN_WARNING,
+                         "Cannot unregister from major no %d, rc = %d",
+                         major,
+                         rc);
+
 		return rc;
 	} else {
 		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
@@ -874,20 +917,23 @@
 dasd_device_t *
 dasd_device_from_kdev (kdev_t kdev)
 {
-	major_info_t *major_info = NULL;
+	major_info_t *major_info;
+        dasd_device_t *device;
 	struct list_head *l;
 	unsigned long flags;
 
+        device = NULL;
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	list_for_each (l, &dasd_major_info[0].list) {
+	list_for_each (l, &dasd_major_info) {
 		major_info = list_entry (l, major_info_t, list);
-		if (major_info->gendisk.major == MAJOR (kdev))
+		if (major_info->gendisk.major == MAJOR (kdev)) {
+                        device = major_info->dasd_device[MINOR (kdev) >>
+                                                         DASD_PARTN_BITS];
 			break;
+                }
 	}
 	spin_unlock_irqrestore (&dasd_major_lock, flags);
-	if (major_info != &dasd_major_info[0])
-		return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS];
-	return NULL;
+        return device;
 }
 
 /*
@@ -900,21 +946,29 @@
 dasd_device_from_devno (int devno)
 {
 	major_info_t *major_info;
+        dasd_device_t **device;
 	struct list_head *l;
-	int devindex = dasd_devindex_from_devno (devno);
+	int devindex;
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	list_for_each (l, &dasd_major_info[0].list) {
+        devindex = dasd_devindex_from_devno (devno);
+        if (devindex < 0) {
+                spin_unlock_irqrestore (&dasd_major_lock, flags);
+                return NULL;
+        }
+
+        device = NULL;
+	list_for_each (l, &dasd_major_info) {
 		major_info = list_entry (l, major_info_t, list);
 		if (devindex < DASD_PER_MAJOR) {
-			spin_unlock_irqrestore (&dasd_major_lock, flags);
-			return &major_info->dasd_device[devindex];
+                        device = &major_info->dasd_device[devindex];
+                        break;
 		}
 		devindex -= DASD_PER_MAJOR;
 	}
 	spin_unlock_irqrestore (&dasd_major_lock, flags);
-	return NULL;
+	return device;
 }
 
 /*
@@ -945,9 +999,33 @@
 	return -ENODEV;
 }
 
+/*
+ * function: dasd_check_bp_block
+ * checks the blocksize and returns 0 if valid.
+ */
+
+static int
+dasd_check_bp_block (dasd_device_t *device)
+{
+        int rc;
 
+        switch (device->sizes.bp_block) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                rc = 0;
+                break;
+        default:
+                rc = -EMEDIUMTYPE;
+        }
+        
+        return rc;
+}
 
-/* SECTION: managing dasd disciplines */
+/********************************************************************************
+ * SECTION: managing dasd disciplines 
+ ********************************************************************************/
 
 /* anchor and spinlock for list of disciplines */
 static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
@@ -955,14 +1033,18 @@
 
 /*
  * function dasd_discipline_enq
- * chains the discpline given as argument to the head of disiplines
- * head chaining policy is required to allow module disciplines to
- * be preferred against those, who are statically linked
+ * chains the discpline given as argument to the tail of disiplines.
+ * Exception: DIAG is always queued to the head, to ensure that CMS RESERVED
+ * minidisks are invariably accessed using DIAG.
  */
 static inline void
-dasd_discipline_enq (dasd_discipline_t * d)
+dasd_discipline_enq (dasd_discipline_t *discipline)
 {
-    list_add(&d->list, &dasd_disc_head);
+        if (strncmp (discipline->name, "DIAG", 4) == 0) {
+                list_add (&discipline->list, &dasd_disc_head);
+        } else {
+                list_add_tail (&discipline->list, &dasd_disc_head);
+        }
 }
 
 /*
@@ -970,59 +1052,88 @@
  * removes the discipline given as argument from the list of disciplines
  */
 static inline void
-dasd_discipline_deq (dasd_discipline_t * d)
+dasd_discipline_deq (dasd_discipline_t * discipline)
 {
-        list_del(&d->list);
+        if (&discipline->list) {
+                list_del (&discipline->list);
+        }
 }
 
 void
-dasd_discipline_add (dasd_discipline_t * d)
+dasd_discipline_add (dasd_discipline_t * discipline)
 {
         unsigned long flags;
         MOD_INC_USE_COUNT;
 	spin_lock_irqsave (&discipline_lock,flags);
-        dasd_discipline_enq (d);
+        dasd_discipline_enq (discipline);
 	spin_unlock_irqrestore (&discipline_lock,flags);
-        dasd_enable_ranges (&dasd_range_head, d, DASD_STATE_ONLINE);
+
+        dasd_enable_ranges (&dasd_range_head, 
+                            discipline, 
+                            DASD_STATE_ONLINE);
 }
 
-void dasd_discipline_del (dasd_discipline_t * d)
+void dasd_discipline_del (dasd_discipline_t * discipline)
 {
         unsigned long flags;
+
+        dasd_disable_ranges(&dasd_range_head,
+                            discipline, 
+                            DASD_STATE_DEL, 
+                            1);
+
 	spin_lock_irqsave (&discipline_lock,flags);
-        dasd_disable_ranges(&dasd_range_head, d, DASD_STATE_DEL, 1);
-        dasd_discipline_deq (d);
+        dasd_discipline_deq (discipline);
 	spin_unlock_irqrestore (&discipline_lock,flags);
         MOD_DEC_USE_COUNT;
 }
 
+/*
+ * function dasd_find_disc
+ * checks the list of disciplines for the first one able to access the device
+ */
 static inline dasd_discipline_t *
-dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d)
+dasd_find_disc (dasd_device_t * device, dasd_discipline_t *discipline)
 {
         dasd_discipline_t *t;
-        struct list_head *l = d ? &d->list : dasd_disc_head.next;
+        struct list_head *l = discipline ? 
+                              &discipline->list : dasd_disc_head.next;
+
         do {
                 t = list_entry(l,dasd_discipline_t,list);
+
                 if ( ( t->id_check == NULL ||
                        t->id_check (&device->devinfo) == 0 ) &&
                      ( t->check_characteristics == NULL ||
                        t->check_characteristics (device) == 0 ) )
                         break;
                 l = l->next;
-                if ( d || 
+                if ( discipline || 
                      l == &dasd_disc_head ) {
                         t = NULL;
                         break;
                 }
          } while ( 1 );
+
 	return t;
 }
 
-/* SECTION: profiling stuff */
+/********************************************************************************
+ * SECTION: profiling stuff 
+ ********************************************************************************/
+
+#ifdef CONFIG_PROC_FS
 
 static dasd_profile_info_t dasd_global_profile;
+#endif  /* CONFIG_PROC_FS */
 
 #ifdef DASD_PROFILE
+
+#define DASD_PROFILE_ON  1
+#define DASD_PROFILE_OFF 0
+
+static unsigned int dasd_profile_level = DASD_PROFILE_OFF;
+
 /*
  * macro: dasd_profile_add_counter
  * increments counter in global and local profiling structures
@@ -1032,7 +1143,7 @@
 { \
         int ind; \
         long help; \
-	for (ind = 0, help = value >> 3; \
+	for (ind = 0, help = value >> 2; \
              ind < 31 && help; \
              help = help >> 1, ind++) {} \
 	dasd_global_profile.counter[ind]++; \
@@ -1086,56 +1197,134 @@
 	dasd_profile_add_counter (irqtime / sectors, dasd_io_time2ps, device);
 	dasd_profile_add_counter (endtime, dasd_io_time3, device);
 }
-#endif
+#endif /* DASD_PROFILE */
 
-/* SECTION: All the gendisk stuff */
+/********************************************************************************
+ * SECTION: All the gendisk stuff 
+ ********************************************************************************/
 
 
-/* SECTION: Managing wrappers for ccwcache */
+/********************************************************************************
+ * SECTION: Managing wrappers for ccwcache 
+ ********************************************************************************/
 
 /*
  * function dasd_alloc_request
  * tries to return space for a channel program of length cplength with
  * additional data of size datasize.
- * If the ccwcache cannot fulfill the request it tries the emergeny requests
- * before giving up finally
+ * If the ccwcache cannot fulfill the request it tries the lowmem requests
+ * before giving up finally.
  * FIXME: initialization of ccw_req_t should be done by function of ccwcache
  */
 ccw_req_t *
-dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device)
+dasd_alloc_request (char *magic, int cplength, int datasize, 
+                    dasd_device_t *device)
 {
-	ccw_req_t *rv = NULL;
+	ccw_req_t *cqr;
+        unsigned long size_needed;
+	unsigned long data_offset, ccw_offset;
+        dasd_lowmem_t *lowmem;
+ 
+        if ((cqr = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
+                return cqr;
+        }
+
+	/* Sanity checks */
+	if (magic == NULL || datasize > PAGE_SIZE ||
+            cplength == 0 || (cplength * sizeof(ccw1_t)) > PAGE_SIZE)
+		BUG();
 
-	if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
-		return rv;
+        /* use lowmem page only for ERP or */
+        /* if there are less than 2 requests on queue */
+        if (device->queue.head != NULL &&
+            device->queue.head->next != NULL &&
+            device->queue.head->status != CQR_STATUS_ERROR) {
+                return NULL;
+        }
+
+	/* We try to keep things together in memory */
+	size_needed = (sizeof (ccw_req_t) + 7) & (~7L);
+	data_offset = ccw_offset = 0;
+	if (size_needed + datasize <= PAGE_SIZE) {
+		/* Keep data with the request */
+		data_offset = size_needed;
+		size_needed += (datasize + 7) & (~7L);
+	}
+	if (size_needed + cplength*sizeof(ccw1_t) <= PAGE_SIZE) {
+		/* Keep CCWs with request */
+		ccw_offset = size_needed;
+		size_needed += (cplength*sizeof(ccw1_t)) & (~7L);
 	}
-	if ((((sizeof (ccw_req_t) + 7) & -8) +
-	     cplength * sizeof (ccw1_t) + datasize) > PAGE_SIZE) {
-		BUG ();
+        
+        /* take page from lowmem_pool for request */
+        list_for_each_entry (lowmem, &device->lowmem_pool, list) {
+                list_del (&lowmem->list);
+                cqr = (ccw_req_t *) lowmem;
+                memset (cqr, 0, PAGE_SIZE);
+                cqr->flags |= CQR_FLAGS_LM_CQR;
+                break;
+        }
+	if (cqr == NULL)
+		return NULL;
+
+	/* take page from lowmem_pool for the extra data */
+	if (data_offset == 0) {
+
+                list_for_each_entry (lowmem, &device->lowmem_pool, list) {
+                        list_del (&lowmem->list);
+                        cqr->data = (void *) lowmem;
+                        memset (cqr->data, 0, PAGE_SIZE);
+                        break;
+                }
+		if (cqr->data == NULL) {
+			printk(KERN_DEBUG PRINTK_HEADER 
+			       "Couldn't allocate data area\n");
+                        
+                        lowmem = (dasd_lowmem_t *) cqr;
+                        list_add (&lowmem->list, &device->lowmem_pool);
+			return NULL;
 		}
-        if (device->lowmem_cqr==NULL) {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_alloc_request,
-                                         "(%04x) Low memory! Using emergency request %p.",
-                                         device->devinfo.devno,
-                                         device->lowmem_ccws);
-
-                device->lowmem_cqr=device->lowmem_ccws;
-                rv = device->lowmem_ccws;
-		memset (rv, 0, PAGE_SIZE);
-		strncpy ((char *) (&rv->magic), magic, 4);
-		ASCEBC ((char *) (&rv->magic), 4);
-		rv->cplength = cplength;
-		rv->datasize = datasize;
-		rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
-		rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
-        } else {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_alloc_request,
-                                         "(%04x) Refusing emergency mem for request "
-                                         "NULL, already in use at %p.",
-                                         device->devinfo.devno,
-                                         device->lowmem_ccws);
-	}
-	return rv;
+	} else {
+		/* Extra data already allocated with the request */
+		cqr->data = (void *) ((addr_t) cqr + data_offset);
+        }
+
+	/* take page from lowmem_pool for the channel program */
+	if (ccw_offset == 0) {
+
+                list_for_each_entry (lowmem, &device->lowmem_pool, list) {
+                        list_del (&lowmem->list);
+                        cqr->cpaddr = (ccw1_t *) lowmem;
+                        memset (cqr->cpaddr, 0, PAGE_SIZE);
+                        break;
+                }
+
+		if (cqr->cpaddr == NULL) {
+			printk (KERN_DEBUG PRINTK_HEADER
+				"Couldn't allocate channel program area\n");
+			if (data_offset == 0) {
+                                lowmem = (dasd_lowmem_t *) cqr->data;
+                                list_add (&lowmem->list, &device->lowmem_pool);
+                        }
+                        lowmem = (dasd_lowmem_t *) cqr;
+                        list_add (&lowmem->list, &device->lowmem_pool);
+			return NULL;
+		}
+	} else {
+		/* Channel program already allocated with the request */
+		cqr->cpaddr = (ccw1_t *) ((addr_t) cqr + ccw_offset);
+        }
+
+        /* use the remaining memory of the cqr page for IDALs */
+        cqr->lowmem_idal_ptr = (void *) ((addr_t) cqr + size_needed);
+
+	strncpy ((char *)(&cqr->magic), magic, 4);
+
+	ASCEBC((char *)(&cqr->magic), 4);
+	cqr->cplength = cplength;
+	cqr->datasize = datasize;
+
+	return cqr;
 }
 
 /*
@@ -1143,87 +1332,147 @@
  * returns a ccw_req_t to the appropriate cache or emergeny request line
  */
 void
-dasd_free_request (ccw_req_t * request, dasd_device_t* device)
+dasd_free_request (ccw_req_t *cqr, dasd_device_t* device)
 {
+        unsigned long size_needed;
+        dasd_lowmem_t *lowmem;
+
 #ifdef CONFIG_ARCH_S390X
         ccw1_t* ccw;
-        /* clear any idals used for chain */
-        ccw=request->cpaddr-1;
+        /* clear any idals used for chain (might be in lowmen cqr page, */
+        /* in seperate lowmen page or kmalloced */
+        ccw=cqr->cpaddr-1;
         do {
                 ccw++;
-                if ((ccw->cda < (unsigned long) device->lowmem_idals           ) || 
-                    (ccw->cda >= (unsigned long) device->lowmem_idals+PAGE_SIZE)   )
-                        clear_normalized_cda (ccw);
-                else {
-                        if (device->lowmem_idal_ptr != device->lowmem_idals)
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "Freeing emergency idals from request at %p.",
-                                              request);
-                        device->lowmem_idal_ptr = device->lowmem_idals;
-                        device->lowmem_cqr=NULL;
+                if ((cqr->flags & CQR_FLAGS_LM_CQR) &&
+                    (ccw->cda >= (unsigned long) cqr) &&
+                    (ccw->cda < (unsigned long) cqr + PAGE_SIZE)) {
+                    /* IDAL is on the car lowmem page */
+                        continue;
+                }
+
+                if ((cqr->flags & CQR_FLAGS_LM_IDAL) &&
+                    (ccw->cda >= (unsigned long) cqr->lowmem_idal) &&
+                    (ccw->cda < (unsigned long) cqr->lowmem_idal + PAGE_SIZE)) {
+                        /* IDAL is on seperate lowmem page */
+                        continue;
                 }
+
+                /* IDAL was build by set_normalized_cda */
+                clear_normalized_cda (ccw);
+
         } while ((ccw->flags & CCW_FLAG_CC) || 
                  (ccw->flags & CCW_FLAG_DC)   );
 #endif
-        if (request != device->lowmem_ccws) { 
-                /* compare to lowmem_ccws to protect usage of lowmem_cqr for IDAL only ! */
-		ccw_free_request (request);
-        } else {
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "Freeing emergency request at %p",
-                              request);
-                device->lowmem_cqr=NULL;
-	}
+        /* give idal lowmem page back to lowmem_pool */
+        if (cqr->flags & CQR_FLAGS_LM_IDAL) {
+                lowmem = (dasd_lowmem_t *) cqr->lowmem_idal;
+                list_add (&lowmem->list, &device->lowmem_pool);
+                cqr->flags &= ~CQR_FLAGS_LM_IDAL;
+        }
+                
+        /* give cqr lowmem pages back to lowmem_pool */
+        if (cqr->flags & CQR_FLAGS_LM_CQR) { 
+                
+                /* make the same decisions as in dasd_alloc_request */
+                size_needed = (sizeof (ccw_req_t) + 7) & (~7L);
+                if (size_needed + cqr->datasize <= PAGE_SIZE) {
+                        /* We kept the data with the request */
+                        size_needed += (cqr->datasize + 7) & (~7L);
+                } else {
+                        lowmem = (dasd_lowmem_t *) cqr->data;
+                        list_add (&lowmem->list, &device->lowmem_pool);
+                }
+                
+                if (size_needed + cqr->cplength * sizeof(ccw1_t) > PAGE_SIZE) {
+                        /* We didn't keep the CCWs with request */
+                        lowmem = (dasd_lowmem_t *) cqr->cpaddr;
+                        list_add (&lowmem->list, &device->lowmem_pool);
+                }
+                lowmem = (dasd_lowmem_t *) cqr;
+                list_add (&lowmem->list, &device->lowmem_pool);
+	} else {
+                ccw_free_request (cqr);
+        }
 }
 
+/*
+ * function dasd_set_normalized_cda
+ * calls set_normalized_cda to build IDALs.
+ * If this did not work because of low memory, we try to use memory from the 
+ * lowmem pool.
+ */
 int
-dasd_set_normalized_cda (ccw1_t * cp, unsigned long address, 
-                         ccw_req_t* request, dasd_device_t* device )
+dasd_set_normalized_cda (ccw1_t *cp, unsigned long address, 
+                         ccw_req_t *cqr, dasd_device_t *device)
 {
 #ifdef CONFIG_ARCH_S390X
+        int rc;
 	int nridaws;
+        dasd_lowmem_t *lowmem;
         int count = cp->count;
         
-        if (set_normalized_cda (cp, address)!=-ENOMEM) {
-                return 0;
-        }
-
-        if ((device->lowmem_cqr!=NULL) && (device->lowmem_cqr!=request)) {
-                DASD_MESSAGE (KERN_WARNING, device, 
-                              "Refusing emergency idals for request %p, memory"
-                              " is already in use for request %p",
-                              request,
-                              device->lowmem_cqr);
-                return -ENOMEM;
-        }
-        device->lowmem_cqr=request;
-        if (device->lowmem_idal_ptr == device->lowmem_idals) {
-            DASD_MESSAGE (KERN_WARNING,device, 
-                          "Low memory! Using emergency IDALs for request %p.\n",
-                          request);
+        /* use lowmem idal page if already assinged */
+        if (!(cqr->flags & CQR_FLAGS_LM_IDAL)) {
+                rc = set_normalized_cda (cp, (void *)address);
+                if (rc !=-ENOMEM) {
+                        return rc;
+                }
         }
+        
+        /* get number of idal words needed */
         nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
 		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
-	if ( device->lowmem_idal_ptr>=device->lowmem_idals + PAGE_SIZE ) {
-		/* Ouch! No Idals left for emergency request */
-		BUG();
-	}
+
+        /* check if we need an additional IDALs page */
+	if (!(cqr->flags & CQR_FLAGS_LM_IDAL)) {
+                /* we got no lowmem cqr page OR */
+                /* there is no space left for IDALs */
+                if ((!(cqr->flags & CQR_FLAGS_LM_CQR)) ||
+                    ((cqr->lowmem_idal_ptr + nridaws * sizeof(unsigned long)) > 
+                     ((void *) cqr + PAGE_SIZE))) {
+                        
+                        /* use lowmem page only for ERP or */
+                        /* if there are less than 2 requests on queue */
+                        if (device->queue.head != NULL &&
+                            device->queue.head->next != NULL &&
+                            device->queue.head->status != CQR_STATUS_ERROR) {
+                                return -ENOMEM;
+                        }
+                       
+                        list_for_each_entry (lowmem, &device->lowmem_pool, 
+                                             list) {
+                                list_del (&lowmem->list);
+                                cqr->lowmem_idal = (void *)lowmem;
+                                cqr->lowmem_idal_ptr  = (void *) lowmem;
+                                memset (cqr->lowmem_idal, 0, PAGE_SIZE);
+                                cqr->flags |= CQR_FLAGS_LM_IDAL;
+                                break;
+                        }
+                }
+                
+        }
+        
+        /* now we (should) have an valid lowmem_idal_ptr and enough space for */
+        /* the IDALs - fill the idals table */
 	cp->flags |= CCW_FLAG_IDA;
-	cp->cda = (__u32)(unsigned long)device->lowmem_idal_ptr;
+	cp->cda = (__u32)(unsigned long)cqr->lowmem_idal_ptr;
         do {
-		*((long*)device->lowmem_idal_ptr) = address;
-		address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
+		*((long*)cqr->lowmem_idal_ptr) = address;
+		address  = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
+                cqr->lowmem_idal_ptr += sizeof(unsigned long);
 		nridaws --;
-                device->lowmem_idal_ptr += sizeof(unsigned long);
         } while ( nridaws > 0 );
 #else 
-        cp -> cda = address;
+        cp->cda = address;
 #endif
 	return 0;
 }
 
 
-/* SECTION: (de)queueing of requests to channel program queues */
+/********************************************************************************
+ * SECTION: (de)queueing of requests to channel program queues 
+ ********************************************************************************/
 
 /*
  * function dasd_chanq_enq
@@ -1245,22 +1494,26 @@
 
        
 #ifdef DASD_PROFILE
-        /* save profile information for non erp cqr */
-        if (cqr->refers == NULL) {
-                unsigned int  counter = 0;
-                ccw_req_t     *ptr;
-                dasd_device_t *device = cqr->device;
-
-                /* count the length of the chanq for statistics */
-                for (ptr = q->head; 
-                     ptr->next != NULL && counter <=31; 
-                     ptr = ptr->next) {
-                        counter++;
-                }                
-                
-                dasd_global_profile.dasd_io_nr_req[counter]++;
-                device->profile.dasd_io_nr_req[counter]++;
-        }
+        if (dasd_profile_level == DASD_PROFILE_ON) {
+
+                /* save profile information for non erp cqr */
+                if (cqr->refers == NULL) {
+                        unsigned int  counter = 0;
+                        ccw_req_t     *ptr;
+                        dasd_device_t *device = cqr->device;
+                        
+                        /* count the length of the chanq for statistics */
+                        for (ptr = q->head; 
+                             ptr->next != NULL && counter <=31; 
+                             ptr = ptr->next) {
+                                counter++;
+                        }                
+                        
+                        dasd_global_profile.dasd_io_nr_req[counter]++;
+                        device->profile.dasd_io_nr_req[counter]++;
+                }
+
+        } /* end if DASD_PROFILE_ON */
 #endif 
 }
 
@@ -1276,7 +1529,10 @@
 	q->head = cqr;
 	if (q->tail == NULL)
 		q->tail = cqr;
-	check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+
+	check_then_set (&cqr->status, 
+                        CQR_STATUS_FILLED, 
+                        CQR_STATUS_QUEUED);
 }
 
 /*
@@ -1302,7 +1558,7 @@
 		while (prev && prev->next != cqr)
 			prev = prev->next;
 		if (prev == NULL)
-			return;
+			return; /* request not in chanq */
 		prev->next = cqr->next;
 		if (prev->next == NULL)
 			q->tail = prev;
@@ -1310,7 +1566,87 @@
 	cqr->next = NULL;
 }
 
-/* SECTION: Managing the device queues etc. */
+/********************************************************************************
+ * SECTION: Managing the device queues etc. 
+ ********************************************************************************/
+
+/*
+ * DASD_RESREL_TIMEOUT
+ *
+ * A timer is used to suspend the current reserve/release request 
+ * if it doesn't return within a certain time.
+ */
+void
+dasd_resrel_timeout (unsigned long cqr_ptr)
+{
+        dasd_device_t *device = ((ccw_req_t *) cqr_ptr)->device;
+        ccw_req_t     *cqr;
+	unsigned long flags;
+
+	s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                   flags);
+        cqr = device->queue.head;
+
+        switch (cqr->status) {
+        case CQR_STATUS_FILLED:
+        case CQR_STATUS_QUEUED:
+                /* request was not started - just set to failed */
+                cqr->status = CQR_STATUS_FAILED;
+                break;
+
+        case CQR_STATUS_IN_IO:
+        case CQR_STATUS_ERROR:        
+                if (device->discipline->term_IO (cqr) != 0);
+                        cqr->status = CQR_STATUS_FAILED;
+                break;
+
+        default:
+                ; /* DONE and FAILED are ok */
+        }
+
+        dasd_schedule_bh (device);
+
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
+                                        flags);
+
+} /* end dasd_resrel_timeout */
+
+/*
+ * Call unconditional reserve to break the reserve of an other system.
+ * Timeout the request if it doesn't succseed within a certain time.
+ */
+static int 
+dasd_steal_lock (dasd_device_t *device)
+{
+        ccw_req_t *cqr;
+        int rc = 0;
+
+        if (!device->discipline->steal_lock) 
+                rc = -EINVAL;
+        
+        cqr = device->discipline->steal_lock (device);
+        
+        if (cqr) {
+                struct timer_list res_timer;
+                
+                init_timer(&res_timer);
+                res_timer.function = dasd_resrel_timeout; 
+                res_timer.data     = (unsigned long) cqr;
+                res_timer.expires  = jiffies + 4 * HZ; 
+                add_timer(&res_timer);
+                
+                rc = dasd_sleep_on_immediate (cqr);
+                
+                del_timer_sync(&res_timer); 
+                dasd_free_request (cqr, 
+                                   device);
+        } else {
+                rc = -ENOMEM;
+        }
+
+        return rc;
+
+} /* end dasd_steal_lock */
 
 /*
  * DASD_TERM_IO
@@ -1331,55 +1667,57 @@
 		BUG ();
 	}
 	irq = device->devinfo.irq;
-	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
-		DASD_MESSAGE (KERN_WARNING, device,
-			      " ccw_req_t 0x%08x magic doesn't match"
-			      " discipline 0x%08x\n",
-			      cqr->magic,
-			      *(unsigned int *) device->discipline->name);
+	if (strncmp ((char *) &cqr->magic, 
+                     device->discipline->ebcname, 4)) {
+
+		DEV_MESSAGE (KERN_WARNING, device,
+                             " ccw_req_t 0x%08x magic doesn't match"
+                             " discipline 0x%08x",
+                             cqr->magic,
+                             *(unsigned int *) device->discipline->name);
+
 		return -EINVAL;
 	}
         
         while ((retries < 5                    ) &&
                (cqr->status == CQR_STATUS_IN_IO)   ) {
 
-                if ( retries < 2 )
-                        rc = halt_IO(irq, (long)cqr, 
-                                     cqr->options | DOIO_WAIT_FOR_INTERRUPT);
-                else
-                        rc = clear_IO(irq, (long)cqr, 
-                                      cqr->options | DOIO_WAIT_FOR_INTERRUPT);
-
+                rc = clear_IO (irq, 
+                               (long)cqr, 
+                               cqr->options);
+                
                 switch (rc) {
                 case 0:         /* termination successful */
                         check_then_set (&cqr->status,
                                         CQR_STATUS_IN_IO, 
                                         CQR_STATUS_FAILED);
                         
-                        asm volatile ("STCK %0":"=m" (cqr->stopclk));
+                        cqr->stopclk = get_clock ();
+
                         break;
                 case -ENODEV:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "device gone, retry\n");
+                        DBF_DEV_EVENT (DBF_ERR, device, "%s",
+                                       "device gone, retry");
                         break;
                 case -EIO:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "I/O error, retry\n");
+                        DBF_DEV_EVENT (DBF_ERR, device, "%s",
+                                       "I/O error, retry");
                         break;
                 case -EBUSY:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "device busy, retry later\n");
+                        DBF_DEV_EVENT (DBF_ERR, device, "%s",
+                                       "device busy, retry later");
                         break;
                 default:
-                        DASD_MESSAGE (KERN_ERR, device,
-                                      "line %d unknown RC=%d, please report"
-                                      " to linux390@de.ibm.com\n", 
-                                      __LINE__, 
-                                      rc);
+                        DEV_MESSAGE (KERN_ERR, device,
+                                     "line %d unknown RC=%d, please "
+                                     "report to linux390@de.ibm.com", 
+                                     __LINE__, 
+                                     rc);
                         BUG ();
                         break;
                 }
 
+                dasd_schedule_bh (device);
                 retries ++;
         }
 	return rc;
@@ -1401,27 +1739,30 @@
 		BUG ();
 	}
 	irq = device->devinfo.irq;
-	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
-		DASD_MESSAGE (KERN_WARNING, device,
-			      " ccw_req_t 0x%08x magic doesn't match"
-			      " discipline 0x%08x\n",
-			      cqr->magic,
-			      *(unsigned int *) device->discipline->name);
+	if (strncmp ((char *) &cqr->magic, 
+                     device->discipline->ebcname, 4)) {
+
+		DEV_MESSAGE (KERN_ERR, device,
+                             " ccw_req_t 0x%08x magic doesn't match"
+                             " discipline 0x%08x",
+                             cqr->magic,
+                             *(unsigned int *) device->discipline->name);
+
 		return -EINVAL;
 	}
 
-	asm volatile ("STCK %0":"=m" (now));
-        cqr->startclk = now;
+	now = get_clock ();
 
-	rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
+        cqr->startclk = now;
+        if (device->accessible)
+                rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
+        else
+                rc = -EBUSY;
 
 	switch (rc) {
 	case 0:
                 if (cqr->options & DOIO_WAIT_FOR_INTERRUPT) {
                         /* request already finished (synchronous IO) */
-                        DASD_MESSAGE (KERN_ERR, device, "%s",
-                                      " do_IO finished request... "
-                                      "DOIO_WAIT_FOR_INTERRUPT was set");
                         check_then_set (&cqr->status,
                                         CQR_STATUS_QUEUED, 
                                         CQR_STATUS_DONE);
@@ -1436,12 +1777,22 @@
                 }
 		break;
 	case -EBUSY:
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "device busy, retry later\n");
+		DBF_DEV_EVENT (DBF_ERR, device, "%s",
+                               "device busy, retry later");
+
+                if (!timer_pending(&device->timer)) {
+                        init_timer (&device->timer);
+                        device->timer.function = dasd_schedule_bh_timed; 
+                        device->timer.data     = (unsigned long) device;
+                        device->timer.expires  = jiffies + (HZ >> 4);
+                        add_timer (&device->timer);
+                } else {
+                        mod_timer(&device->timer, jiffies + (HZ >> 4));
+                }
 		break;
 	case -ETIMEDOUT: 
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "request timeout - terminated\n");
+		DBF_DEV_EVENT (DBF_ERR, device, "%s",
+                               "request timeout - terminated");
 	case -ENODEV:
 	case -EIO:
 		check_then_set (&cqr->status,
@@ -1452,9 +1803,11 @@
                 dasd_schedule_bh (device);
 		break;
 	default:
-		DASD_MESSAGE (KERN_ERR, device,
-			      "line %d unknown RC=%d, please report"
-			      " to linux390@de.ibm.com\n", __LINE__, rc);
+		DEV_MESSAGE (KERN_ERR, device,
+                             "line %d unknown RC=%d, please report"
+                             " to linux390@de.ibm.com",
+                             __LINE__, 
+                             rc);
 		BUG ();
 		break;
 	}
@@ -1465,43 +1818,83 @@
 /*
  * function dasd_sleep_on_req
  * attempts to start the IO and waits for completion
- * FIXME: replace handmade sleeping by wait_event
  */
 int
-dasd_sleep_on_req (ccw_req_t * req)
+dasd_sleep_on_req (ccw_req_t * cqr)
 {
 	unsigned long flags;
-	int cs;
-	int rc = 0;
-	dasd_device_t *device = (dasd_device_t *) req->device;
+	dasd_device_t *device = (dasd_device_t *) cqr->device;
 
-        if ( signal_pending(current) ) {
+        if (signal_pending(current)) {
                 return -ERESTARTSYS;
         }
-	s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-	dasd_chanq_enq (&device->queue, req);
+	s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                   flags);
+        
+	dasd_chanq_enq (&device->queue, 
+                        cqr);
+
 	/* let the bh start the request to keep them in order */
 	dasd_schedule_bh (device);
-	do {
-		s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-		wait_event ( device->wait_q,
-			     (((cs = req->status) == CQR_STATUS_DONE) ||
-			     (cs == CQR_STATUS_FAILED) ||
-                             signal_pending(current)));
-		s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-                if ( signal_pending(current) ) {
-                        rc = -ERESTARTSYS;
-		     	if (req->status == CQR_STATUS_IN_IO ) 
-                        	device->discipline->term_IO(req);
-                        break;
-                } else if ( req->status == CQR_STATUS_FAILED) {
-                        rc = -EIO;
-                        break;
-                }
-	} while (cs != CQR_STATUS_DONE && cs != CQR_STATUS_FAILED);
-	s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-	return rc;
-}				/* end dasd_sleep_on_req */
+
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
+                                        flags);
+
+        wait_event (device->wait_q,
+                    cqr->flags & CQR_FLAGS_FINALIZED); 
+
+        if (cqr->status == CQR_STATUS_FAILED) {
+                return -EIO;
+        }
+
+	return 0;
+
+} /* end dasd_sleep_on_req */
+
+/*
+ * function dasd_sleep_on_immediate
+ * same as dasd_sleep_on_req, but attempts to start the IO immediately 
+ * (killing the actual running IO). 
+ */
+static int
+dasd_sleep_on_immediate (ccw_req_t *cqr)
+{
+	unsigned long flags;
+	dasd_device_t *device = (dasd_device_t *) cqr->device;
+
+        if (signal_pending(current))
+                return -ERESTARTSYS;
+
+	s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                   flags);
+        
+        /* terminate currently running IO */
+        if (device->queue.head->status == CQR_STATUS_IN_IO) {
+
+                device->discipline->term_IO (device->queue.head);
+
+                device->queue.head->status = CQR_STATUS_QUEUED;
+        }
+
+	dasd_chanq_enq_head (&device->queue, 
+                             cqr);
+
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh (device);
+
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
+                                        flags);
+        
+        wait_event (device->wait_q,
+                    cqr->flags & CQR_FLAGS_FINALIZED); 
+        
+        if (cqr->status == CQR_STATUS_FAILED) {
+                return -EIO;
+        }
+
+	return 0;
+
+} /* end dasd_sleep_on_immediate */
 
 /*
  * function dasd_end_request
@@ -1547,12 +1940,17 @@
 	unsigned long long now;
 	int rc = 0;
 
-	asm volatile ("STCK %0":"=m" (now));
-	if (cqr->expires && cqr->expires + cqr->startclk < now) {
-		DASD_MESSAGE (KERN_ERR, ((dasd_device_t *) cqr->device),
-			      "IO timeout 0x%08lx%08lx usecs in req %p\n",
-			      (long) (cqr->expires >> 44),
-			      (long) (cqr->expires >> 12), cqr);
+	now = get_clock ();
+
+	if (cqr->expires && 
+            cqr->expires + cqr->startclk < now) {
+
+		DBF_DEV_EVENT (DBF_WARNING, ((dasd_device_t *) cqr->device),
+                               "IO timeout 0x%08lx%08lx usecs in req %p",
+                               (long) (cqr->expires >> 44),
+                               (long) (cqr->expires >> 12), 
+                               cqr);
+
 		cqr->expires <<= 1;
                 rc = -EIO;
 	}
@@ -1569,22 +1967,36 @@
 {
 	dasd_device_t *device = cqr->device;
 
-	asm volatile ("STCK %0":"=m" (cqr->endclk));
+	cqr->endclk = get_clock ();
+
 	if (cqr->req) {
+
 #ifdef DASD_PROFILE
-		dasd_profile_add (cqr);
+                if (dasd_profile_level == DASD_PROFILE_ON) {
+                        dasd_profile_add (cqr);
+                }
 #endif
+
 		dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
 		/* free request if nobody is waiting on it */
 		dasd_free_request (cqr, cqr->device);
 	} else {
-                if ( cqr == device->init_cqr && /* bring late devices online */
-                     device->level <= DASD_STATE_ONLINE ) { 
-                        device->timer.function = dasd_enable_single_device; 
-                        device->timer.data     = (unsigned long) device;
-                        device->timer.expires  = jiffies;
-                        add_timer(&device->timer);
+                if (cqr == device->init_cqr && /* bring late devices online */
+                    device->level <= DASD_STATE_ONLINE ) { 
+                        if (!timer_pending(&device->late_timer)) {
+                                init_timer(&device->late_timer);
+                                device->late_timer.function = dasd_enable_single_device; 
+                                device->late_timer.data     = (unsigned long) device;
+                                device->late_timer.expires  = jiffies;
+                                add_timer(&device->late_timer);
+                        } else {
+                                mod_timer(&device->late_timer, jiffies);
+                        }
+                } else {
+                        /* notify sleep_on_xxx about finished cqr */
+                        cqr->flags |= CQR_FLAGS_FINALIZED;
                 }
+
 		/* notify sleeping task about finished postprocessing */
 		wake_up (&device->wait_q);
                 
@@ -1606,12 +2018,10 @@
 	dasd_chanq_t *qp = &device->queue;
 	int irq = device->devinfo.irq;
 	ccw_req_t *final_requests = NULL;
-	static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
 	int chanq_max_size = DASD_CHANQ_MAX_SIZE;
 	ccw_req_t *cqr = NULL, *temp;
 	dasd_erp_postaction_fn_t erp_postaction;
 
-
 	s390irq_spin_lock_irqsave (irq, flags);
 
 	/* First we dechain the requests, processed with completed status */
@@ -1628,16 +2038,10 @@
 
                         qp->head->retries--; 
 
-			if (qp->head->dstat->flag & DEVSTAT_HALT_FUNCTION) {
-
-                                check_then_set (&qp->head->status,
-                                                CQR_STATUS_ERROR,
-                                                CQR_STATUS_FAILED);
-
-                                asm volatile ("STCK %0":"=m" (qp->head->stopclk));
-
-                        } else if ((device->discipline->erp_action == NULL                          ) ||
-                                   ((erp_action = device->discipline->erp_action (qp->head)) == NULL)   ) {
+			if ((qp->head->dstat == NULL                                         ) ||
+			    ((qp->head->dstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) == 0         ) ||
+			    (device->discipline->erp_action == NULL                          ) ||
+			    ((erp_action = device->discipline->erp_action (qp->head)) == NULL)   ) {
                                 
 				erp_cqr = dasd_default_erp_action (qp->head);
 
@@ -1651,12 +2055,12 @@
 
 			if (qp->head->status == CQR_STATUS_DONE) {
 
-                                DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                                              "ERP successful");
+                                DBF_DEV_EVENT (DBF_NOTICE, device, "%s",
+                                               "ERP successful");
 			} else {
 
-                                DASD_MESSAGE (KERN_ERR, device, "%s",
-                                              "ERP unsuccessful");
+                                DEV_MESSAGE (KERN_WARNING, device, "%s",
+                                             "ERP unsuccessful");
 			}
 
 			if ((device->discipline->erp_postaction == NULL                              )||
@@ -1685,66 +2089,61 @@
 	} /* end while over completed requests */
 
 	if (cqr)
-		cqr->next = NULL;
+		cqr->next = NULL;         /* terminate final_requests queue */
+
 	/* Now clean the requests with final status */
 	while (final_requests) { 
 		temp = final_requests;
 		final_requests = temp->next;
 		dasd_finalize_request (temp);
 	}
+
 	/* Now we try to fetch requests from the request queue */
-	for (temp = cqr; temp != NULL; temp = temp->next)
+	for (temp = qp->head; temp != NULL; temp = temp->next) {
 		if (temp->status == CQR_STATUS_QUEUED)
 			chanq_max_size--;
+        }
+
 	while ((atomic_read(&device->plugged) == 0) &&
+               (queue) &&
                (!queue->plugged) &&
 	       (!list_empty (&queue->queue_head)) &&
-	       (req = dasd_next_request (queue)) != NULL) {
+	       (req = dasd_next_request (queue)) &&
+               (qp->head == NULL || chanq_max_size > 0)) {
 		/* queue empty or certain critera fulfilled -> transfer */
-		if (qp->head == NULL ||
-		    chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) {
-			ccw_req_t *cqr = NULL;
-                        if (is_read_only(device->kdev) && req->cmd == WRITE) {
-
-                                DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler,
-                                                         "(%04x) Rejecting write request %p\n",
-                                                         device->devinfo.devno,
-                                                         req);
+                cqr = NULL;
+                if (is_read_only(device->kdev) && req->cmd == WRITE) {
 
-                                dasd_end_request (req, 0);
-                                dasd_dequeue_request (queue,req);
-                        } else {
-                            /* relocate request according to partition table */
-                            req->sector +=
-                                device->major_info->gendisk.
-                                part[MINOR (req->rq_dev)].start_sect;
-                            cqr = device->discipline->build_cp_from_req (device, req);
-                            if (cqr == NULL) {
-
-                                    DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler,
-                                                             "(%04x) CCW creation failed "
-                                                             "on request %p\n",
-                                                             device->devinfo.devno,
-                                                             req);
-                                    /* revert relocation of request */
-                                    req->sector -=
-                                        device->major_info->gendisk.
-                                        part[MINOR (req->rq_dev)].start_sect;
-                                    break;	/* terminate request queue loop */
-                                    
-                            }
-#ifdef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
-                            chanq_min_size =
-                                (chanq_min_size + req->nr_sectors) >> 1;
-#endif				/* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
-                            dasd_dequeue_request (queue, req);
-                            dasd_chanq_enq (qp, cqr);
+                        DBF_EVENT (DBF_ERR,
+                                   "(%04x) Rejecting write request %p",
+                                   device->devinfo.devno,
+                                   req);
+                        dasd_dequeue_request (queue,req);
+                        dasd_end_request (req, 0);
+                        continue;
+                } 
+                cqr = device->discipline->build_cp_from_req (device, req);
+                        
+                if (cqr == NULL || IS_ERR(cqr)) {
+                        if (cqr == ERR_PTR(-ENOMEM)) {
+                                break;
                         }
-		} else {	/* queue not empty OR criteria not met */
-			break;	/* terminate request queue loop */
-		}
-	}
-	/* we process the requests with non-final status */
+
+                        MESSAGE (KERN_EMERG,
+                                 "(%04x) CCW creation failed "
+                                 "on request %p",
+                                 device->devinfo.devno, req);
+                        dasd_dequeue_request (queue,req);
+                        dasd_end_request (req, 0);
+                        continue;
+                }
+                dasd_dequeue_request (queue, req);
+                dasd_chanq_enq (qp, cqr);
+                chanq_max_size--;
+
+	}
+
+	/* we process the requests with non-final status */
 	if (qp->head) {
 		switch (qp->head->status) {
 		case CQR_STATUS_QUEUED:
@@ -1764,6 +2163,10 @@
 			/* just wait */
 			break;
 		default:
+                        MESSAGE (KERN_EMERG,
+                                 "invalid cqr (%p) detected with status %02x ",
+                                 qp->head,
+                                 qp->head->status);
 			BUG ();
 		}
 	}
@@ -1786,6 +2189,18 @@
 }
 
 /*
+ * function dasd_schedule_bh_timed
+ * retriggers the dasd_schedule_bh function (called by timer queue)
+ */
+void 
+dasd_schedule_bh_timed (unsigned long device_ptr)
+{
+        dasd_device_t *device = (dasd_device_t *) device_ptr;
+
+        dasd_schedule_bh (device);
+}
+
+/*
  * function dasd_schedule_bh
  * schedules the request_fn to run with next run_bh cycle
  */
@@ -1842,30 +2257,43 @@
 
 	if (device_addr == NULL) {
 
-		printk (KERN_DEBUG PRINTK_HEADER
-			"unable to find device for state change pending "
-			"interrupt: devno%04x\n", 
-                        stat->devno);
+		MESSAGE (KERN_DEBUG,
+                         "unable to find device for state change pending "
+                         "interrupt: devno%04x", 
+                         stat->devno);
                 return;
 	} 
 
         /* re-activate first request in queue */
         cqr = (*device_addr)->queue.head;
+
+	if (cqr == NULL) {
+		MESSAGE (KERN_DEBUG,
+			 "got state change pending interrupt on"
+			 "idle device: %04x",
+			 stat->devno);
+		return;
+	}
         
         if (cqr->status == CQR_STATUS_PENDING) {
                 
-                DASD_MESSAGE (KERN_DEBUG, (*device_addr), "%s",
-                              "device request queue restarted by "
-                              "state change pending interrupt\n");
+                DEV_MESSAGE (KERN_DEBUG, (*device_addr), "%s",
+                             "device request queue restarted by "
+                             "state change pending interrupt");
                 
-                del_timer (&(*device_addr)->timer);
+                del_timer_sync (&(*device_addr)->blocking_timer);
                 
                 check_then_set (&cqr->status,
                                 CQR_STATUS_PENDING, CQR_STATUS_QUEUED);
                 
-                dasd_schedule_bh (*device_addr);
-                
         }
+	if (cqr->status == CQR_STATUS_IN_IO) {
+		cqr->status = CQR_STATUS_QUEUED;
+		DEV_MESSAGE (KERN_WARNING, (*device_addr), "%s",
+				"redriving state change pending condition while in IO");
+	}
+
+        dasd_schedule_bh (*device_addr);
 
 } /* end dasd_handle_state_change_pending */
 
@@ -1879,50 +2307,50 @@
 	int ip;
 	ccw_req_t *cqr;
 	dasd_device_t *device;
-        unsigned long long now;
-	dasd_era_t era = dasd_era_none; /* default is everything is okay */
+	dasd_era_t era;
 	devstat_t *stat = (devstat_t *)ds;
 
         if (stat == NULL) {
                 BUG();
 	}
-        DASD_DRIVER_DEBUG_EVENT (6, dasd_int_handler,
-                                 "Interrupt: IRQ %02x, stat %02x, devno %04x",
-                                 irq,
-                                 stat->dstat,
-                                 stat->devno);
-        asm volatile ("STCK %0":"=m" (now));
+
+        DBF_EVENT (DBF_DEBUG,
+                   "Int: IRQ %02x, CS/DS %04x, flag %08x, devno %04x, ip %08x",
+                   irq,
+                   ((stat->cstat<<8)|stat->dstat),
+                   stat->flag,
+                   stat->devno,
+                   stat->intparm);
 
         /* first of all check for state change pending interrupt */
         if ((stat->dstat & DEV_STAT_ATTENTION ) && 
             (stat->dstat & DEV_STAT_DEV_END   ) &&
             (stat->dstat & DEV_STAT_UNIT_EXCEP)   ) {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "State change Interrupt: %04x",
-                                         stat->devno);
+
+                DBF_EVENT (DBF_NOTICE,
+                           "State change Interrupt: %04x",
+                           stat->devno);
+
                 dasd_handle_state_change_pending (stat);
                 return;
         }
 
 	ip = stat->intparm;
 	if (!ip) {		/* no intparm: unsolicited interrupt */
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "Unsolicited Interrupt: %04x",
-                                         stat->devno);
-		printk (KERN_DEBUG PRINTK_HEADER
-                        "unsolicited interrupt: irq 0x%x devno %04x\n",
-                        irq,
-                        stat->devno);
+
+		MESSAGE (KERN_DEBUG,
+                         "unsolicited interrupt: irq 0x%x devno %04x",
+                         irq,
+                         stat->devno);
 		return;
 	}
-	if (ip & 0x80000001) {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "spurious Interrupt: %04x",
-                                         stat->devno);
-		printk (KERN_DEBUG PRINTK_HEADER
-                        "spurious interrupt: irq 0x%x devno %04x, parm %08x\n",
-                        irq,
-                        stat->devno,ip);
+
+	if (ip & 0x80000001) {  /* check for invalid 'cqr' address */
+
+		MESSAGE (KERN_DEBUG,
+                         "spurious interrupt: irq 0x%x devno %04x, parm %08x",
+                         irq,
+                         stat->devno,ip);
 		return;
 	}
 
@@ -1930,19 +2358,16 @@
 
         /* check status - the request might have been killed because of dyn dettach */
 	if (cqr->status != CQR_STATUS_IN_IO) {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "invalid status %02x on device %04x",
-                                         cqr->status,
-                                         stat->devno);
-
-		printk (KERN_DEBUG PRINTK_HEADER
-                        "invalid status: irq 0x%x devno %04x, status %02x\n",
-                        irq,
-                        stat->devno,
-                        cqr->status);
+
+		MESSAGE (KERN_DEBUG,
+                         "invalid status: irq 0x%x devno %04x, status %02x",
+                         irq,
+                         stat->devno,
+                         cqr->status);
 		return;
 	}
 
+        /* some consistency checks */
 	device = (dasd_device_t *) cqr->device;
 	if (device == NULL || 
             device != ds-offsetof(dasd_device_t,dev_status)) {
@@ -1955,73 +2380,98 @@
                 BUG();
 	}
 
-        /* first of all lets try to find out the appropriate era_action */
-        DASD_DEVICE_DEBUG_EVENT (4, device," Int: CS/DS 0x%04x",
-                                 ((stat->cstat<<8)|stat->dstat));
-
 	/* first of all lets try to find out the appropriate era_action */
-	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
-	    stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-		/* anything abnormal ? */
-		if (device->discipline->examine_error == NULL ||
-		    stat->flag & DEVSTAT_HALT_FUNCTION) {
-			era = dasd_era_fatal;
-		} else {
-			era = device->discipline->examine_error (cqr, stat);
-		}
-                DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d",
-                                         era);
-	}
-        if ( era == dasd_era_none ) {
-                check_then_set(&cqr->status, 
-                               CQR_STATUS_IN_IO, 
-                               CQR_STATUS_DONE);
-
-                cqr->stopclk=now;
-		/* start the next queued request if possible -> fast_io */
-                if (cqr->next &&
-                    cqr->next->status == CQR_STATUS_QUEUED) {
-                        if (device->discipline->start_IO (cqr->next) != 0) {
-                                printk (KERN_WARNING PRINTK_HEADER
-                                        "Interrupt fastpath failed!\n");
-                        } 
-                }
-        } else { /* error */
+        if (stat->flag & DEVSTAT_HALT_FUNCTION) {
+                era = dasd_era_fatal;
+                
+	} else if (stat->flag  & DEVSTAT_FINAL_STATUS &&
+                   stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+                   stat->cstat == 0) {
+		/* received 'ok' for running IO */
+		era = dasd_era_none;
+                
+        } else if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+                /* got sense data */
 		if (cqr->dstat == NULL)
 			cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
 		if (cqr->dstat) {
 			memcpy (cqr->dstat, stat, sizeof (devstat_t));
 		} else {
-			PRINT_ERR ("no memory for dstat...ignoring\n");
+			MESSAGE (KERN_DEBUG, "%s",
+                                 "no memory for dstat...ignoring");
 		}
-
 #ifdef ERP_DEBUG
-		/* dump sense data */
-		if (device->discipline            && 
+		if (device->discipline            &&
                     device->discipline->dump_sense  ) {
-
+                        
                         device->discipline->dump_sense (device, 
                                                         cqr);
 		}
 #endif
+                if (device->discipline->examine_error == NULL) {
+                        era = dasd_era_recover;
+                } else {
+                        era = device->discipline->examine_error (cqr, stat);
+                }
 
-		switch (era) {
-		case dasd_era_fatal:
-			check_then_set (&cqr->status, 
-                                        CQR_STATUS_IN_IO,
-					CQR_STATUS_FAILED);
+        } else  if (stat->flag & DEVSTAT_NOT_OPER) {
+                /* path became offline or similar                          */
+                /* => retry to see if there are any other pathes available */
+                DEV_MESSAGE (KERN_DEBUG, device, "%s",
+                             "Device or a path became not operational while in IO");
+		era = dasd_era_recover;
+
+        } else if (stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) ||
+                   stat->cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN) ) {
+                /* received device state apart from (channel end & device end)  */
+                /* OR any kind of channel check (e.g. IFCC, DATA_CHECK or ..... */
+                /* we got no sense data, therefore we just retry                */
+                DEV_MESSAGE (KERN_DEBUG, device,
+                             "Status without sense (IFCC,...) CS/DS %04x flag %08x",
+			     ((stat->cstat<<8)|stat->dstat),
+			     stat->flag);
+		era = dasd_era_recover;
 
-                        cqr->stopclk = now;
-			break;
-		case dasd_era_recover:
-			check_then_set (&cqr->status, 
-                                        CQR_STATUS_IN_IO,
-					CQR_STATUS_ERROR);
-			break;
-		default:
-			BUG ();
+        } else {
+                /* any other kind of interrupt  - just retry */
+                DEV_MESSAGE (KERN_DEBUG, device,
+                             "Got unclassified interrupt CS/DS %04x flag %08x",
+                             ((stat->cstat<<8)|stat->dstat),
+                             stat->flag);
+                era = dasd_era_recover;
+        }
+        
+        switch (era) {
+        case dasd_era_none:
+		check_then_set(&cqr->status, 
+			       CQR_STATUS_IN_IO, 
+			       CQR_STATUS_DONE);
+		cqr->stopclk = get_clock ();
+		/* start the next queued request if possible -> fast_io */
+		if (cqr->next &&
+		    cqr->next->status == CQR_STATUS_QUEUED) {
+			if (device->discipline->start_IO (cqr->next) != 0) {
+				MESSAGE (KERN_WARNING, "%s",
+					 "Interrupt fastpath failed!");
+			} 
 		}
-	}
+		break;
+        case dasd_era_fatal:
+		check_then_set (&cqr->status, 
+				CQR_STATUS_IN_IO,
+				CQR_STATUS_FAILED);
+		cqr->stopclk = get_clock ();
+		break;
+        case dasd_era_recover:
+		check_then_set (&cqr->status, 
+				CQR_STATUS_IN_IO,
+				CQR_STATUS_ERROR);
+		break;
+        default:
+		BUG ();
+        }
+	
+	/* handle special device initialization request */
         if ( cqr == device->init_cqr &&
              ( cqr->status == CQR_STATUS_DONE ||
                cqr->status == CQR_STATUS_FAILED )){
@@ -2033,59 +2483,47 @@
 
 } /* end dasd_int_handler */
 
-/* SECTION: Some stuff related to error recovery */
+/********************************************************************************
+ * SECTION: Some stuff related to error recovery 
+ ********************************************************************************/
 
 /*
  * DEFAULT_ERP_ACTION
  *
  * DESCRIPTION
- *   sets up the default-ERP ccw_req_t, namely one, which performs a TIC
- *   to the original channel program with a retry counter of 16
+ *   just retries the current cqr
  *
  * PARAMETER
  *   cqr                failed CQR
  *
  * RETURN VALUES
- *   erp                CQR performing the ERP
+ *   cqr                modified CQR
  */
 ccw_req_t *
 dasd_default_erp_action (ccw_req_t * cqr)
 {
 
         dasd_device_t *device = cqr->device;
-	ccw_req_t     *erp    = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device);
-
-	printk (KERN_DEBUG PRINTK_HEADER "Default ERP called... \n");
-
-	if (!erp) {
-
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "Unable to allocate ERP request");
-                
+        // just retry - there is nothing to save ... I got no sense data....
+        if (cqr->retries > 0) {
+                DEV_MESSAGE (KERN_DEBUG, device, 
+                             "default ERP called (%i retries left)",
+                             cqr->retries);
+ 
                 check_then_set (&cqr->status,
                                 CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-
-                asm volatile ("STCK %0":"=m" (cqr->stopclk));
-
-                return cqr;
-	}
-
-	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda = (__u32) (addr_t) cqr->cpaddr;
-	erp->function = dasd_default_erp_action;
-	erp->refers = cqr;
-	erp->device = cqr->device;
-	erp->magic = cqr->magic;
-	erp->retries = 16;
-
-	erp->status = CQR_STATUS_FILLED;
-
-        dasd_chanq_enq_head (&device->queue,
-                             erp);
-
-	return erp;
-
+                                CQR_STATUS_QUEUED);
+        } else {
+                DEV_MESSAGE (KERN_WARNING, device, "%s",
+			     "default ERP called (NO retry left)");
+		
+		check_then_set (&cqr->status,
+				CQR_STATUS_ERROR,
+				CQR_STATUS_FAILED);
+		
+		cqr->stopclk = get_clock ();
+        }
+        return cqr;
 } /* end dasd_default_erp_action */
 
 /*
@@ -2141,26 +2579,21 @@
 	/* save ptr to original cqr */
 	cqr = erp;
 
-	/* set corresponding status to original cqr */
+	/* set corresponding status for original cqr */
 	if (success) {
-
-		check_then_set (&cqr->status, 
-                                CQR_STATUS_ERROR,
-				CQR_STATUS_DONE);
+                cqr->status = CQR_STATUS_DONE;
 	} else {
-
-		check_then_set (&cqr->status,
-				CQR_STATUS_ERROR, 
-                                CQR_STATUS_FAILED);
-
-                asm volatile ("STCK %0":"=m" (cqr->stopclk));
+                cqr->status  = CQR_STATUS_FAILED;
+                cqr->stopclk = get_clock ();
 	}
 
 	return cqr;
 
 } /* end default_erp_postaction */
 
-/* SECTION: The helpers of the struct file_operations */
+/********************************************************************************
+ * SECTION: The helpers of the struct file_operations 
+ ********************************************************************************/
 
 /*
  * function dasd_format
@@ -2175,39 +2608,41 @@
 {
 	int rc = 0;
 	int openct = atomic_read (&device->open_count);
+        ccw_req_t *req;
 
 	if (openct > 1) {
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "dasd_format: device is open! expect errors.");
+
+		DEV_MESSAGE (KERN_WARNING, device, "%s",
+                             "dasd_format: device is open! "
+                             "expect errors.");
 	}
-	DASD_MESSAGE (KERN_INFO, device,
-		      "formatting units %d to %d (%d B blocks) flags %d",
-		      fdata->start_unit, 
-                      fdata->stop_unit,
-		      fdata->blksize, 
-                      fdata->intensity);
+
+	DBF_DEV_EVENT (DBF_NOTICE, device,
+                       "formatting units %d to %d (%d B blocks) flags %d",
+                       fdata->start_unit, 
+                       fdata->stop_unit,
+                       fdata->blksize, 
+                       fdata->intensity);
+
 	while ((!rc) && (fdata->start_unit <= fdata->stop_unit)) {
-                ccw_req_t *req;
-                dasd_format_fn_t ffn = device->discipline->format_device;
-		ffn = device->discipline->format_device;
-		if (ffn == NULL)
+
+		if (device->discipline->format_device == NULL)
 			break;
-		req = ffn (device, fdata);
+
+		req = device->discipline->format_device (device, fdata);
 		if (req == NULL) {
 			rc = -ENOMEM;
 			break;
 		}
 		if ((rc = dasd_sleep_on_req (req)) != 0) {
-			DASD_MESSAGE (KERN_WARNING, device,
-				      " Formatting of unit %d failed with rc = %d\n",
-				      fdata->start_unit, rc);
+
+			DEV_MESSAGE (KERN_WARNING, device,
+                                     " Formatting of unit %d failed "
+                                     "with rc = %d",
+                                     fdata->start_unit, rc);
 			break;
 		} 
 		dasd_free_request (req, device);	/* request is no longer used */
-	        if ( signal_pending(current) ) {
-			rc = -ERESTARTSYS;
-			break;		
-                }
 		fdata->start_unit++;
 	}
 	return rc;
@@ -2258,6 +2693,9 @@
 	return 0;
 }
 
+/*
+ * handle the re-read partition table IOCTL (BLKRRPART)
+ */ 
 static int
 dasd_revalidate (dasd_device_t * device)
 {
@@ -2267,8 +2705,9 @@
 	int openct = atomic_read (&device->open_count);
 	int start = MINOR (kdev);
 	if (openct != 1) {
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "BLKRRPART: device is open! expect errors.");
+
+		DEV_MESSAGE (KERN_WARNING, device, "%s",
+                             "BLKRRPART: device is open! expect errors.");
 	}
 	for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
                 int major = device->major_info->gendisk.major;
@@ -2279,6 +2718,15 @@
         return rc;
 
 }
+
+/*
+ * function do_dasd_ioctl
+ * Implementation of the DASD API.
+ * Changes to the API should be binary compatible to privous versions
+ * of the user-space applications by means of any already existing tool 
+ * (e.g. dasdfmt) must work with the new kernel API.
+ */
+
 static int
 do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 {
@@ -2287,10 +2735,12 @@
 	major_info_t *major_info;
 
 	if (!device) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as device (%d:%d)\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
+
+		MESSAGE (KERN_WARNING,
+                         "No device registered as device (%d:%d)",
+                         MAJOR (inp->i_rdev), 
+                         MINOR (inp->i_rdev));
+
 		return -EINVAL;
 	}
 	if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
@@ -2298,225 +2748,356 @@
 		return -EINVAL;
 	}
 	major_info = device->major_info;
-#if 0
-	printk (KERN_DEBUG PRINTK_HEADER
-		"ioctl 0x%08x %s'0x%x'%d(%d) on /dev/%s (%d:%d,"
-		" devno 0x%04x on irq %d) with data %8lx\n",
-		no,
-		_IOC_DIR (no) == _IOC_NONE ? "0" :
-		_IOC_DIR (no) == _IOC_READ ? "r" :
-		_IOC_DIR (no) == _IOC_WRITE ? "w" :
-		_IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
-		_IOC_TYPE (no),
-                _IOC_NR (no),
-                _IOC_SIZE (no),
-		device->name, 
-                MAJOR (inp->i_rdev), 
-                MINOR (inp->i_rdev),
-		device->devinfo.devno, 
-                device->devinfo.irq, 
-                data);
-#endif
+
+	DBF_DEV_EVENT (DBF_DEBUG, device,
+                 "ioctl 0x%08x %s'0x%x'%d(%d) with data %8lx",
+                 no,
+                 (_IOC_DIR (no) == _IOC_NONE ? "0" :
+                  _IOC_DIR (no) == _IOC_READ ? "r" :
+                  _IOC_DIR (no) == _IOC_WRITE ? "w" :
+                  _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u"),
+                 _IOC_TYPE (no),
+                 _IOC_NR (no),
+                 _IOC_SIZE (no),
+                 data);
+
 	switch (no) {
-        case DASDAPIVER: {
-			int ver = DASD_API_VERSION;
-			rc = put_user(ver, (int *) data);
-			break;
+        case DASDAPIVER: {      /* retrun dasd API version */
+                int ver = DASD_API_VERSION;
+                rc = put_user(ver, (int *) data);
+                break;
+        }
+	case BLKGETSIZE: {	/* Return device size in # of sectors */
+                long blocks = major_info->gendisk.sizes 
+                        [MINOR (inp->i_rdev)] << 1;
+                rc = put_user(blocks, (long *) data);
+                break;
+        }
+	case BLKGETSIZE64:{ 
+                u64 blocks = major_info->gendisk.sizes 
+                        [MINOR (inp->i_rdev)];
+                rc = put_user(blocks << 10, (u64 *) data);
+                break;
+        }
+	case BLKRRPART: {       /* reread partition table */
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+                rc = dasd_revalidate (device);
+                break;
         }
-	case BLKGETSIZE:{	/* Return device size */
-			long blocks = major_info->gendisk.sizes 
-                                      [MINOR (inp->i_rdev)] << 1;
-			rc = put_user(blocks, (long *) data);
-			break;
-		}
-	case BLKGETSIZE64:{
-			u64 blocks = major_info->gendisk.sizes 
-                                      [MINOR (inp->i_rdev)];
-			rc = put_user(blocks << 10, (u64 *) data);
-			break;
-		}
-	case BLKRRPART:{
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			rc = dasd_revalidate (device);
-			break;
-		}
-	case HDIO_GETGEO:{
-			struct hd_geometry geo = { 0, };
-			rc = dasd_fillgeo (inp->i_rdev, &geo);
-			if (rc)
-				break;
+	case HDIO_GETGEO: {     /* return disk geometry */
+                struct hd_geometry geo = { 0, };
+                rc = dasd_fillgeo (inp->i_rdev, &geo);
+                if (rc)
+                        break;
 
-			rc = copy_to_user ((struct hd_geometry *) data, &geo,
-					   sizeof (struct hd_geometry));
-			if (rc)
-				rc = -EFAULT;
-			break;
-		}
-	case BIODASDDISABLE:{
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-                        if ( device->level > DASD_STATE_ACCEPT) {
-                                dasd_deactivate_queue(device);
-                                if ( device->request_queue)
-                                        dasd_flush_request_queues(device,0);
-                                dasd_flush_chanq(device,0);
-                                dasd_disable_blkdev(device);
-                                dasd_set_device_level (device->devinfo.devno, 
-                                                       device->discipline, 
-                                                       DASD_STATE_ACCEPT);
-                        }
+                rc = copy_to_user ((struct hd_geometry *) data, &geo,
+                                   sizeof (struct hd_geometry));
+                if (rc)
+                        rc = -EFAULT;
+                break;
+        }
+	case BIODASDDISABLE: {  /* disable device */
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
                         break;
+                }
+
+                if ( device->level > DASD_STATE_ACCEPT) {
+                        dasd_deactivate_queue(device);
+                        if ( device->request_queue)
+                                dasd_flush_request_queues(device,0);
+                        dasd_flush_chanq(device,0);
+                        dasd_disable_blkdev(device);
+                        dasd_set_device_level (device->devinfo.devno, 
+                                               device->discipline, 
+                                               DASD_STATE_ACCEPT);
+                }
+
+                break;
         }
-	case BIODASDENABLE:{
-                        dasd_range_t range = { 
-                                from: device->devinfo.devno,
-                                to: device->devinfo.devno 
-                        };
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-                        dasd_enable_ranges (&range, device->discipline, 0);
+	case BIODASDENABLE: {   /* enable device */
+                dasd_range_t range = { 
+                        from: device->devinfo.devno,
+                        to: device->devinfo.devno 
+                };
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
                         break;
+                }
+                dasd_enable_ranges (&range, device->discipline, 0);
+                break;
         }
-	case BIODASDFMT:{
-			/* fdata == NULL is no longer a valid arg to dasd_format ! */
-			int partn = MINOR (inp->i_rdev) &
-			    ((1 << major_info->gendisk.minor_shift) - 1);
-			format_data_t fdata;
+	case BIODASDFMT: {      /* format device */
+                /* fdata == NULL is no longer a valid arg to dasd_format ! */
+                int partn = MINOR (inp->i_rdev) &
+                        ((1 << major_info->gendisk.minor_shift) - 1);
+                format_data_t fdata;
+                
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+                if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+                        rc = -EROFS;
+                        break;
+                }
+                if (!data) {
+                        rc = -EINVAL;
+                        break;
+                }
+                rc = copy_from_user (&fdata, (void *) data,
+                                     sizeof (format_data_t));
+                if (rc) {
+                        rc = -EFAULT;
+                        break;
+                }
+                if (partn != 0) {
 
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-                        if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
-                                rc = -EROFS;
-                                break;
+                        DEV_MESSAGE (KERN_WARNING, device, "%s",
+                                     "Cannot low-level format a partition");
+
+                        return -EINVAL;
+                }
+                rc = dasd_format (device, &fdata);
+                break;
+        }
+	case BIODASDSATTR: {      /* Set Attributes (cache operations) */
+
+                attrib_data_t attrib;
+                
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+
+                if (!data) {
+                        rc = -EINVAL;
+                        break;
+                }
+                        
+                if (!device->discipline->set_attrib) {
+                        rc = -EINVAL;
+                        break;
+                }
+                        
+                rc = copy_from_user (&attrib, (void *) data,
+                                     sizeof (attrib_data_t));
+                if (rc) {
+                        rc = -EFAULT;
+                        break;
+                }
+
+                rc = device->discipline->set_attrib (device,
+                                                     &attrib);
+                break;
+        }
+	case BIODASDPRRST: {    /* reset device profile information */
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+                memset (&device->profile, 0,
+                        sizeof (dasd_profile_info_t));
+                break;
+        }
+	case BIODASDPRRD: {     /* return device profile information */
+                rc = copy_to_user((long *)data,
+                                  (long *)&device->profile,
+                                  sizeof(dasd_profile_info_t));
+                if (rc)
+                        rc = -EFAULT;
+                break;
+        }
+	case BIODASDRSRV: {     /* reserve device */
+                ccw_req_t *cqr;
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+
+                if (!device->discipline->reserve) {
+                        rc = -EINVAL;
+                        break;
+                }
+                
+                cqr = device->discipline->reserve (device);
+
+                if (cqr) {
+                        struct timer_list res_timer;
+                        
+                        init_timer (&res_timer);
+                        res_timer.function = dasd_resrel_timeout; 
+                        res_timer.data     = (unsigned long) cqr;
+                        res_timer.expires  = jiffies + 2 * HZ; 
+                        add_timer (&res_timer);
+                        
+                        rc = dasd_sleep_on_immediate (cqr);
+
+                        del_timer_sync (&res_timer); 
+                        dasd_free_request (cqr, 
+                                           device);
+                } else {
+                        rc = -ENOMEM;
+                }
+                break;
+        }
+	case BIODASDRLSE: {     /* release device */
+                ccw_req_t *cqr;
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+
+                if (!device->discipline->release) {
+                        rc = -EINVAL;
+                        break;
+                }
+
+                cqr = device->discipline->release (device);
+                
+                if (cqr) {
+                        struct timer_list rel_timer;
+                        
+                        init_timer (&rel_timer);
+                        rel_timer.function = dasd_resrel_timeout; 
+                        rel_timer.data     = (unsigned long) cqr;
+                        rel_timer.expires  = jiffies + 2 * HZ; 
+                        add_timer (&rel_timer);
+                        
+                        rc = dasd_sleep_on_immediate (cqr);
+
+                        del_timer_sync (&rel_timer); /* in case of interrupt */
+                        dasd_free_request (cqr, 
+                                           device);
+                } else {
+                        rc = -ENOMEM;
+                }
+                break;
+        }
+	case BIODASDSLCK: {     /* steal lock - unconditional reserve device */
+                if (!capable (CAP_SYS_ADMIN)) {
+                        rc = -EACCES;
+                        break;
+                }
+                        
+                rc = dasd_steal_lock (device);
+                break;
+        }
+	case BIODASDINFO:       /* return dasd information */
+	case BIODASDINFO2: {    /* return dasd information2 (incl. format and features) */
+                dasd_information2_t dasd_info;
+                
+                unsigned long flags;
+
+                if (!device->discipline->fill_info) {
+                        rc = -EINVAL;
+                        break;
+                }
+
+                rc = device->discipline->fill_info (device, 
+                                                    &dasd_info);
+
+                dasd_info.label_block = device->sizes.pt_block;
+                dasd_info.devno = device->devinfo.devno;
+                dasd_info.schid = device->devinfo.irq;
+                dasd_info.cu_type = device->devinfo.sid_data.cu_type;
+                dasd_info.cu_model = device->devinfo.sid_data.cu_model;
+                dasd_info.dev_type = device->devinfo.sid_data.dev_type;
+                dasd_info.dev_model = device->devinfo.sid_data.dev_model;
+                dasd_info.open_count =
+                        atomic_read (&device->open_count);
+                dasd_info.status = device->level;
+                
+                /* check if device is really formatted - LDL / CDL was returned by 'fill_info' */
+                if ((device->level < DASD_STATE_READY) ||
+                    (dasd_check_bp_block (device)    )   ) {
+                        dasd_info.format = DASD_FORMAT_NONE;
+                }
+                
+                dasd_info.features = 
+                        dasd_features_from_devno (device->devinfo.devno);
+                
+                if (device->discipline) {
+                        memcpy (dasd_info.type,
+                                device->discipline->name, 4);
+                } else {
+                        memcpy (dasd_info.type, "none", 4);
+                }
+                dasd_info.req_queue_len = 0;
+                dasd_info.chanq_len = 0;
+
+                if ((device->request_queue            ) &&
+                    (device->request_queue->request_fn)   ) {
+                        struct list_head *l;
+                        ccw_req_t *cqr = device->queue.head;
+                        spin_lock_irqsave (&io_request_lock, flags);
+                        list_for_each (l,
+                                       &device->request_queue->
+                                       queue_head) {
+                                dasd_info.req_queue_len++;
                         }
-			if (!data) {
-				rc = -EINVAL;
-				break;
-			}
-			rc = copy_from_user (&fdata, (void *) data,
-					     sizeof (format_data_t));
-			if (rc) {
-				rc = -EFAULT;
-				break;
-			}
-			if (partn != 0) {
-				DASD_MESSAGE (KERN_WARNING, device, "%s",
-					      "Cannot low-level format a partition");
-				return -EINVAL;
-			}
-			rc = dasd_format (device, &fdata);
-			break;
-		}
-	case BIODASDPRRST:{     /* reset device profile information */
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			memset (&device->profile, 0,
-				sizeof (dasd_profile_info_t));
-			break;
-		}
-	case BIODASDPRRD:{      /* retrun device profile information */
-			rc = copy_to_user((long *)data,
-					  (long *)&device->profile,
-					  sizeof(dasd_profile_info_t));
-			if (rc)
-				rc = -EFAULT;
-			break;
-		}
-	case BIODASDRSRV:{      /* reserve */
-			ccw_req_t *req;
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			req = device->discipline->reserve (device);
-			rc = dasd_sleep_on_req (req);
-			dasd_free_request (req, device);
-			break;
-		}
-	case BIODASDRLSE:{      /* release */
-			ccw_req_t *req;
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			req = device->discipline->release (device);
-			rc = dasd_sleep_on_req (req);
-			dasd_free_request (req, device);
-			break;
-		}
-	case BIODASDSLCK:{      /* steal lock - unconditional reserve */
-			ccw_req_t *req;
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			req = device->discipline->steal_lock (device);
-			rc = dasd_sleep_on_req (req);
-			dasd_free_request (req, device);
-			break;
-		}
-	case BIODASDINFO:{
-			dasd_information_t dasd_info;
-			unsigned long flags;
-			rc = device->discipline->fill_info (device, &dasd_info);
-                        dasd_info.label_block = device->sizes.pt_block;
-			dasd_info.devno = device->devinfo.devno;
-			dasd_info.schid = device->devinfo.irq;
-			dasd_info.cu_type = device->devinfo.sid_data.cu_type;
-			dasd_info.cu_model = device->devinfo.sid_data.cu_model;
-			dasd_info.dev_type = device->devinfo.sid_data.dev_type;
-			dasd_info.dev_model = device->devinfo.sid_data.dev_model;
-			dasd_info.open_count =
-			    atomic_read (&device->open_count);
-			dasd_info.status = device->level;
-			if (device->discipline) {
-				memcpy (dasd_info.type,
-					device->discipline->name, 4);
-			} else {
-				memcpy (dasd_info.type, "none", 4);
-			}
-			dasd_info.req_queue_len = 0;
-			dasd_info.chanq_len = 0;
-			if (device->request_queue->request_fn) {
-				struct list_head *l;
-				ccw_req_t *cqr = device->queue.head;
-				spin_lock_irqsave (&io_request_lock, flags);
-				list_for_each (l,
-					       &device->request_queue->
-					       queue_head) {
-					dasd_info.req_queue_len++;
-				}
-				spin_unlock_irqrestore (&io_request_lock,
-							flags);
-				s390irq_spin_lock_irqsave (device->devinfo.irq,
-							   flags);
-				while (cqr) {
-					cqr = cqr->next;
-					dasd_info.chanq_len++;
-				}
-				s390irq_spin_unlock_irqrestore (device->devinfo.
-								irq, flags);
-			}
-			rc =
-			    copy_to_user ((long *) data, (long *) &dasd_info,
-					  sizeof (dasd_information_t));
-			if (rc)
-				rc = -EFAULT;
-			break;
-		}
+                        spin_unlock_irqrestore (&io_request_lock,
+                                                flags);
+                        s390irq_spin_lock_irqsave (device->devinfo.irq,
+                                                   flags);
+                        while (cqr) {
+                                cqr = cqr->next;
+                                dasd_info.chanq_len++;
+                        }
+                        s390irq_spin_unlock_irqrestore (device->devinfo.
+                                                        irq, flags);
+                }
+
+                rc = copy_to_user ((long *) data, (long *) &dasd_info,
+                                   ((no == (unsigned int) BIODASDINFO2) ? 
+                                    sizeof (dasd_information2_t) : 
+                                    sizeof (dasd_information_t)));
+
+                if (rc)
+                        rc = -EFAULT;
+                break;
+        }
+        case BIODASDPSRD: { /* Performance Statistics Read */
+                
+                ccw_req_t              *cqr;
+                dasd_rssd_perf_stats_t *stats;
+
+                if ((!device->discipline->read_stats) ||
+                    (!device->discipline->ret_stats )   ) {
+                        rc = -EINVAL;
+                        break;
+                }
+
+                cqr = device->discipline->read_stats (device); 
+                
+                if (cqr) {
+                        
+                        if ((rc = dasd_sleep_on_req (cqr)) == 0) {
+                                
+                                if ((stats = device->discipline->ret_stats (cqr)) != NULL) {
+                                        
+                                        rc = copy_to_user ((long *) data,
+                                                           (long *) stats,
+                                                           sizeof (dasd_rssd_perf_stats_t));
+                                } else {
+                                        
+                                        rc = -EFAULT;
+                             }
+                        }
+                        
+                        dasd_free_request (cqr, 
+                                           device);
+                        
+                } else {
+                        rc = -ENOMEM;
+                }
+                break;
+        }
 #if 0 /* needed for XFS */
-	case BLKBSZSET:{
+	case BLKBSZSET: {
 		int bsz;
 		rc = copy_from_user ((long *)&bsz,(long *)data,sizeof(int));
 		if ( rc ) {
@@ -2528,10 +3109,46 @@
 				rc = -EINVAL; 
 		}
 		break;
-		}
+        }
 #endif /* 0 */
+	case BLKROSET: {
+                int intval;
+                dasd_range_t *temp;
+                int devindex = 0;
+                unsigned long flags;
+                struct list_head *l;
+                int major=MAJOR(device->kdev);
+                int minor;
+
+                if (!capable(CAP_SYS_ADMIN))
+                        return -EACCES;
+                if (inp->i_rdev != device->kdev)
+                        // ro setting is not allowed for partitions
+                        return -EINVAL; 
+                if (get_user(intval, (int *)(data)))
+                        return -EFAULT;
+                spin_lock_irqsave (&range_lock, flags);
+                list_for_each (l, &dasd_range_head.list) {
+                        temp = list_entry (l, dasd_range_t, list);
+                        if (device->devinfo.devno >= temp->from && device->devinfo.devno <= temp->to) {
+                                spin_unlock_irqrestore (&range_lock, flags);
+                                if (intval)
+                                        temp->features |= DASD_FEATURE_READONLY;
+                                else
+                                        temp->features &= ~DASD_FEATURE_READONLY;
+                                goto continue_blkroset;
+                        }
+                        devindex += temp->to - temp->from + 1;
+                }
+                spin_unlock_irqrestore (&range_lock, flags);
+                return(-ENODEV);
+continue_blkroset:
+                for (minor = MINOR(device->kdev); minor < MINOR(device->kdev) + (1 << DASD_PARTN_BITS); minor++)
+                        set_device_ro(MKDEV(major,minor), intval);
+                return 0;
+        }
+	case BLKBSZGET:
 	case BLKSSZGET:
-	case BLKROSET:
 	case BLKROGET:
 	case BLKRASET:
 	case BLKRAGET:
@@ -2541,37 +3158,41 @@
 	case BLKELVSET:
 		return blk_ioctl (inp->i_rdev, no, data);
 		break;
-	default:{
+	default: {
 
-			dasd_ioctl_list_t *old = dasd_find_ioctl (no);
-			if (old) {
-				if ( old->owner )
-					__MOD_INC_USE_COUNT(old->owner);
-				rc = old->handler (inp, no, data);
-				if ( old->owner )
-					__MOD_DEC_USE_COUNT(old->owner);
-			} else {
-				DASD_MESSAGE (KERN_INFO, device,
-					      "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
-					      no,
-					      _IOC_DIR (no) == _IOC_NONE ? "0" :
-					      _IOC_DIR (no) == _IOC_READ ? "r" :
-					      _IOC_DIR (no) == _IOC_WRITE ? "w" : 
-                                              _IOC_DIR (no) == 
-                                              (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
-                                              _IOC_TYPE (no),
-					      _IOC_NR (no), 
-                                              _IOC_SIZE (no),
-					      data);
-				rc = -ENOTTY;
-			}
-			break;
+                dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+                if (old) {
+                        if ( old->owner )
+                                __MOD_INC_USE_COUNT(old->owner);
+                        rc = old->handler (inp, no, data);
+                        if ( old->owner )
+                                __MOD_DEC_USE_COUNT(old->owner);
+                } else {
+
+                        DBF_DEV_EVENT (DBF_INFO, device,
+                                       "unknown ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx",
+                                       no,
+                                       (_IOC_DIR (no) == _IOC_NONE ? "0" :
+                                        _IOC_DIR (no) == _IOC_READ ? "r" :
+                                        _IOC_DIR (no) == _IOC_WRITE ? "w" : 
+                                        _IOC_DIR (no) == 
+                                        (_IOC_READ | _IOC_WRITE) ? "rw" : "u"),
+                                       _IOC_TYPE (no),
+                                       _IOC_NR (no), 
+                                       _IOC_SIZE (no),
+                                       data);
+
+                        rc = -ENOTTY;
+                }
+                break;
 		}
 	}
 	return rc;
 }
 
-/* SECTION: The members of the struct file_operations */
+/********************************************************************************
+ * SECTION: The members of the struct file_operations 
+ ********************************************************************************/
 
 static int
 dasd_ioctl (struct inode *inp, struct file *filp,
@@ -2597,26 +3218,32 @@
                 goto fail;
 	}
 	if (dasd_probeonly) {
-		printk ("\n" KERN_INFO PRINTK_HEADER
-			"No access to device (%d:%d) due to probeonly mode\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
+
+		MESSAGE (KERN_INFO,
+                         "No access to device (%d:%d) due to probeonly mode",
+                         MAJOR (inp->i_rdev), 
+                         MINOR (inp->i_rdev));
+
 		rc = -EPERM;
                 goto fail;
 	}
         spin_lock_irqsave(&discipline_lock,flags);
 	device = dasd_device_from_kdev (inp->i_rdev);
 	if (!device) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as (%d:%d)\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
+
+		MESSAGE (KERN_WARNING,
+                         "No device registered as (%d:%d)",
+                         MAJOR (inp->i_rdev), 
+                         MINOR (inp->i_rdev));
+
 		rc = -ENODEV;
                 goto unlock;
 	}
 	if (device->level <= DASD_STATE_ACCEPT ) {
-		DASD_MESSAGE (KERN_WARNING, device, " %s", 
-                              " Cannot open unrecognized device\n");
+
+		DBF_DEV_EVENT (DBF_ERR, device, " %s", 
+                               " Cannot open unrecognized device");
+
 		rc = -ENODEV;
                 goto unlock;
 	}
@@ -2648,17 +3275,21 @@
 	}
 	device = dasd_device_from_kdev (inp->i_rdev);
 	if (!device) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as %d:%d\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
+
+		MESSAGE (KERN_WARNING,
+                         "No device registered as %d:%d",
+                         MAJOR (inp->i_rdev), 
+                         MINOR (inp->i_rdev));
+
 		rc = -EINVAL;
                 goto out;
 	}
 
 	if (device->level < DASD_STATE_ACCEPT ) {
-		DASD_MESSAGE (KERN_WARNING, device, " %s",
-                              " Cannot release unrecognized device\n");
+
+		DBF_DEV_EVENT (DBF_ERR, device, " %s",
+                               " Cannot release unrecognized device");
+
 		rc = -ENODEV;
                 goto out;
 	}
@@ -2669,8 +3300,9 @@
                         __MOD_DEC_USE_COUNT(device->discipline->owner);
 	} else if ( count == -1 ) { /* paranoia only */
                 atomic_set (&device->open_count,0);
-                printk (KERN_WARNING PRINTK_HEADER
-                        "release called with open count==0\n");
+
+                MESSAGE (KERN_WARNING, "%s",
+                         "release called with open count==0");
         }
  out:
 	return rc;
@@ -2685,7 +3317,9 @@
 	ioctl:dasd_ioctl,
 };
 
-/* SECTION: Management of device list */
+/********************************************************************************
+ * SECTION: Management of device list 
+ ********************************************************************************/
 int
 dasd_fillgeo(int kdev,struct hd_geometry *geo)
 {
@@ -2708,24 +3342,27 @@
 int
 dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
 {
-	int len = 0;
+        major_info_t *major_info;
+        struct list_head *l;
 	char first, second, third;
+	int len;
 
-	if (hd) {
-		major_info_t *major_info = NULL;
-		struct list_head *l;
-
-		list_for_each (l, &dasd_major_info[0].list) {
-			major_info = list_entry (l, major_info_t, list);
-			if (&major_info->gendisk == hd) {
-				break;
-			}
-			index += DASD_PER_MAJOR;
-		}
-		if (major_info == &dasd_major_info[0]) {
-			return -EINVAL;
-		}
-	}
+        if (hd == NULL)
+                return -EINVAL;
+
+        major_info = NULL;
+        list_for_each (l, &dasd_major_info) {
+                major_info = list_entry (l, major_info_t, list);
+                if (&major_info->gendisk == hd)
+                        break;
+                index += DASD_PER_MAJOR;
+        }
+        if (major_info == NULL || &major_info->gendisk != hd) { 
+                /* list empty or hd not found in list */
+                return -EINVAL;
+        }
+
+        len = 0;
 	third = index % 26;
 	second = ((index - 26) / 26) % 26;
 	first = (((index - 702) / 26) / 26) % 26;
@@ -2777,7 +3414,8 @@
                              cqr->status != CQR_STATUS_FAILED ) {
 
                                 cqr->status = CQR_STATUS_FAILED;
-                                asm volatile ("STCK %0":"=m" (cqr->stopclk));
+
+                                cqr->stopclk = get_clock ();
 
                         }
                         dasd_schedule_bh(device);
@@ -2802,6 +3440,56 @@
         } 
 }
 
+static inline void dasd_do_hotplug_event (dasd_device_t* device, int eventid) {
+#ifdef CONFIG_HOTPLUG
+        int i;
+        char *argv[3], *envp[8];
+        char devno[20],major[20],minor[20],devname[26],action[20];
+
+        /* setup command line arguments */
+        i=0;
+        argv[i++] = hotplug_path;
+        argv[i++] = "dasd";
+        argv[i++] = 0;
+
+        /* minimal environment */
+        i=0;
+        envp[i++] = "HOME=/";
+        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+        
+        /* device information and event*/
+        sprintf (devno, "DEVNO=%04x", device->devinfo.devno);
+        sprintf (major, "MAJOR=%d", MAJOR(device->kdev));
+        sprintf (minor, "MINOR=%d", MINOR(device->kdev));
+        sprintf (devname, "DASDNAME=%s",device->name);
+        switch (eventid) {
+        case DASD_HOTPLUG_EVENT_ADD:
+                sprintf (action,"ACTION=add");
+                break;
+        case DASD_HOTPLUG_EVENT_REMOVE:
+                sprintf (action,"ACTION=remove");
+                break;
+        case DASD_HOTPLUG_EVENT_PARTCHK:
+                sprintf (action,"ACTION=partchk");
+                break;
+        case DASD_HOTPLUG_EVENT_PARTREMOVE:
+                sprintf (action,"ACTION=partremove");
+                break;
+        default:
+                BUG();
+        }
+        envp[i++] = devno;
+        envp[i++] = major;
+        envp[i++] = minor;
+        envp[i++] = devname;
+        envp[i++] = action;
+        envp[i++] = 0;
+        
+        call_usermodehelper (argv [0], argv, envp);
+#endif
+}
+
+
 static int
 dasd_disable_volume ( dasd_device_t * device, int force ) 
 {
@@ -2810,8 +3498,9 @@
         int count = atomic_read (&device->open_count);
         
 	if ( count ) {
-		DASD_MESSAGE (KERN_EMERG, device, "%s",
-			      "device has vanished although it was open!");
+
+		DEV_MESSAGE (KERN_EMERG, device, "%s",
+                             "device has vanished although it was open!");
         }
         if ( force ) {
                 dasd_deactivate_queue(device);
@@ -2824,9 +3513,11 @@
         /* unregister partitions ('ungrok_partitions') */
         devfs_register_partitions(&device->major_info->gendisk,
                                   MINOR(device->kdev),1);
+        dasd_do_hotplug_event (device, DASD_HOTPLUG_EVENT_PARTREMOVE);
         
-        DASD_MESSAGE (KERN_WARNING, device, 
-                      "disabling device, target state: %d",target);
+        DBF_DEV_EVENT (DBF_ERR, device, 
+                       "disabling device, target state: %d",
+                       target);
 
         dasd_set_device_level (device->devinfo.devno, 
                                device->discipline, 
@@ -2836,7 +3527,7 @@
 
 static void
 dasd_disable_ranges (dasd_range_t *range, 
-                     dasd_discipline_t *d,
+                     dasd_discipline_t *discipline,
                      int all, int force ) 
 {
         dasd_range_t *rrange;
@@ -2858,14 +3549,15 @@
                         }
                         device = *dptr;
                         if (device == NULL ||
-                            (d != NULL &&
-                             device -> discipline != d))
+                            (discipline != NULL &&
+                             device -> discipline != discipline))
                                 continue;
                         
                         dasd_disable_volume(device, force);
                 }
                 rrange = list_entry (rrange->list.next, dasd_range_t, list);
         } while ( all && rrange && rrange != range );
+        
 }
 
 static void 
@@ -2877,10 +3569,13 @@
 }
 
 static void
-dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all ) 
+dasd_enable_ranges (dasd_range_t *range, 
+                    dasd_discipline_t *discipline, 
+                    int all) 
 {
         int retries = 0;
 	int j;
+        int do_again;
         kdev_t tempdev;
 	dasd_range_t *rrange;
 
@@ -2888,6 +3583,7 @@
 		return;
         
         do {
+                do_again = 0;
                 if (range == &dasd_range_head) {
                         rrange = list_entry (range->list.next, 
                                              dasd_range_t, list);
@@ -2898,26 +3594,40 @@
                         for (j = rrange->from; j <= rrange->to; j++) {
                                 if ( dasd_devindex_from_devno(j) < 0 )
                                         continue;
-                                dasd_set_device_level (j, d, DASD_STATE_ONLINE);
+                                if (-EAGAIN == dasd_set_device_level 
+                                    (j, discipline, DASD_STATE_ONLINE))
+                                        do_again = 1;
                         }
                         rrange = list_entry (rrange->list.next, dasd_range_t, list);
                 } while ( all && rrange && rrange != range );
 
-                if (atomic_read (&dasd_init_pending) == 0) /* we are done, exit loop */
+                if ((atomic_read (&dasd_init_pending) == 0) &&
+                    (!do_again)) /* we are done, exit loop */
                         break;
 
                 if ( retries == 0 ) {
-                        printk (KERN_INFO PRINTK_HEADER
-                                "waiting for responses...\n");
+
+                        MESSAGE (KERN_INFO, "%s",
+                                 "waiting for responses...");
+
                 } else if ( retries < 5 ) {
-                        printk (KERN_INFO PRINTK_HEADER
-                                "waiting a little bit longer...\n");
+
+                        DBF_EVENT (DBF_NOTICE, "%s",
+                                   "waiting a little bit longer...");
+
                 } else {
-                        printk (KERN_INFO PRINTK_HEADER
-                                "giving up, enable late devices manually!\n");
+
+                        MESSAGE (KERN_INFO, "%s",
+                                 "giving up, enable late devices manually!");
                         break;
                 }
-                interruptible_sleep_on_timeout (&dasd_init_waitq, (1 * HZ));
+
+                /* prevent scheduling if called by bh (timer) */
+                if (!in_interrupt()) {
+                        interruptible_sleep_on_timeout (&dasd_init_waitq, 
+                                                        (1 * HZ)         );
+                }
+
                 retries ++;
         } while (1);
         /* now setup block devices */
@@ -2939,9 +3649,9 @@
                         device = *dptr;
                         if (device == NULL )
                                 continue;
-                        if ( ((d == NULL && device->discipline != NULL) ||
-                              (device->discipline == d )) &&
-                             device->level >= DASD_STATE_READY &&
+                        if ( ((discipline == NULL && device->discipline != NULL) ||
+                              (device->discipline == discipline )) &&
+                             device->level == DASD_STATE_ONLINE &&
                              device->request_queue == NULL ) {
                                 if (dasd_features_from_devno(j)&DASD_FEATURE_READONLY) {
                                         for (tempdev=device->kdev;
@@ -2949,9 +3659,8 @@
                                              tempdev++)
                                                 set_device_ro (tempdev, 1);
 
-                                        printk (KERN_WARNING PRINTK_HEADER 
-                                                "setting read-only mode for device /dev/%s\n",
-                                                device->name);
+                                        DEV_MESSAGE (KERN_WARNING, device, "%s",
+                                                     "setting read-only mode ");
                                 }
                                 dasd_setup_blkdev(device);
                                 dasd_setup_partitions(device);
@@ -2971,13 +3680,17 @@
 static void
 dasd_not_oper_handler (int irq, int status)
 {
-	dasd_device_t *device = NULL;
-	major_info_t *major_info = NULL;
+	dasd_device_t *device;
+	major_info_t *major_info;
+        ccw_req_t* cqr;
 	struct list_head *l;
-	int i, devno = -ENODEV;
+        unsigned long flags;
+	int i, devno;
 
 	/* find out devno of leaving device: CIO has already deleted this information ! */
-	list_for_each (l, &dasd_major_info[0].list) {
+        devno = -ENODEV;
+	device = NULL;
+	list_for_each (l, &dasd_major_info) {
 		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			device = major_info->dasd_device[i];
@@ -2990,17 +3703,44 @@
 			break;
 	}
 
-	DASD_DRIVER_DEBUG_EVENT (5, dasd_not_oper_handler, 
-                                 "called for devno %04x", 
-                                 devno);
-
 	if (devno < 0) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"not_oper_handler called on irq 0x%04x no devno!\n", 
-                        irq);
+
+		MESSAGE (KERN_WARNING,
+                         "not_oper_handler called on irq 0x%04x no devno!", 
+                         irq);
 		return;
 	}
-        dasd_disable_volume(device, 1);
+	switch (status) {
+	case DEVSTAT_DEVICE_GONE:
+	case DEVSTAT_REVALIDATE: //FIXME
+		DEV_MESSAGE (KERN_DEBUG, device, "%s", 
+			"device is gone, disabling it permanently\n");
+        	dasd_disable_volume(device, 1);
+		break;
+	case DEVSTAT_NOT_ACC:
+	case DEVSTAT_NOT_ACC_ERR:
+		DEV_MESSAGE (KERN_DEBUG, device, "%s",
+			"device is not accessible, disabling it temporary\n");                
+                s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                           flags);
+                device->accessible = 0;
+		if (status == DEVSTAT_NOT_ACC_ERR) {
+			cqr = device->queue.head;
+			while (cqr) {
+				if (cqr->status == CQR_STATUS_QUEUED)
+					break;
+				if (cqr->status == CQR_STATUS_IN_IO)
+					cqr->status = CQR_STATUS_QUEUED;
+				cqr = cqr->next;
+			}
+		}
+                s390irq_spin_unlock_irqrestore(device->devinfo.irq, 
+                                               flags);
+
+		break;
+	default:
+		panic ("dasd not operational handler was called with illegal status\n");
+	}
 }
 
 /*
@@ -3014,56 +3754,62 @@
 {
 	int devno;
 	int rc = 0;
-	major_info_t *major_info = NULL;
+	major_info_t *major_info;
         dasd_range_t *rptr,range;
-        dasd_device_t *device = NULL;
+        dasd_device_t *device;
 	struct list_head *l;
+	unsigned long flags;
         int i;
 
+
 	devno = get_devno_by_irq (irq);
 	if (devno == -ENODEV) {
 		rc = -ENODEV;
                 goto out;
 	}
 
-	DASD_DRIVER_DEBUG_EVENT (5, dasd_oper_handler, 
-                                 "called for devno %04x", 
-                                 devno);
-
 	/* find out devno of device */
-	list_for_each (l, &dasd_major_info[0].list) {
+	device = NULL;
+	list_for_each (l, &dasd_major_info) {
 		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			device = major_info->dasd_device[i];
-			if (device && device->devinfo.irq == irq) {
-				devno = device->devinfo.devno;
+			if (device && device->devinfo.irq == irq)
 				break;
-			}
+			else
+                                device = NULL;
 		}
-		if (devno != -ENODEV)
+		if (device)
 			break;
 	}
-	if (devno < 0) {
-                BUG();
-	}
+
         if ( device &&
-             device->level == DASD_STATE_READY ) {
-            dasd_set_device_level (device->devinfo.devno, 
-                                   device->discipline, DASD_STATE_ONLINE);
+             (device->level == DASD_STATE_ONLINE) &&
+	     (!device->accessible) ) {
+                s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                           flags);
+		DEV_MESSAGE (KERN_DEBUG, device, "%s",
+			"device is accessible again, reenabling it\n");
+                device->accessible = 1;
+                s390irq_spin_unlock_irqrestore(device->devinfo.irq, 
+                                               flags);
 
+		    
+                dasd_schedule_bh(device);
         } else {
-            if (dasd_autodetect) {
-		rptr = dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
-                if ( rptr == NULL ) {
-                    rc = -ENOMEM;
-                    goto out;
-                }
-            } else {
-                range.from = devno;
-                range.to = devno;
-                rptr = &range;
-            }
-            dasd_enable_ranges (rptr, NULL, 0);
+
+                if (dasd_autodetect) {
+                        rptr = dasd_add_range (devno, devno, DASD_FEATURE_DEFAULT);
+                        if ( rptr == NULL ) {
+                                rc = -ENOMEM;
+                                goto out;
+                        }
+                } else {
+                        range.from = devno;
+                        range.to = devno;
+                        rptr = &range;
+                }
+                dasd_enable_ranges (rptr, NULL, 0);
         }
  out:
 	return rc;
@@ -3075,13 +3821,16 @@
 {
         dasd_device_t **device_addr;
 
-	DASD_DRIVER_DEBUG_EVENT (1, dasd_find_device_addr, 
-                                 "devno %04x", 
-                                 devno);
+	DBF_EVENT (DBF_INFO, 
+                   "devno %04x", 
+                   devno);
+
 	if ( dasd_devindex_from_devno (devno) < 0 ) {
-                DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, 
-                                             "no dasd: devno %04x",
-                                             devno);
+
+                DBF_EXC (DBF_ALERT, 
+                         "no dasd: devno %04x",
+                         devno);
+
 		return NULL;
 	}
         /* allocate major numbers on demand  for new devices */
@@ -3090,9 +3839,8 @@
 
 		if ((rc = dasd_register_major (NULL)) <= 0) {
 
-                        DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, 
-                                                     "%s",
-                                                     "out of major numbers!");
+                        DBF_EXC (DBF_ALERT, "%s",
+                                 "out of major numbers!");
                         break;
 		}
 	}
@@ -3100,86 +3848,110 @@
 }
 
 static inline int
-dasd_state_del_to_new (dasd_device_t **addr ) 
+dasd_state_del_to_new (dasd_device_t **addr, int devno) 
 {
+        int i;
         dasd_device_t* device;
-        int rc = 0;
-	if (*addr == NULL) { /* allocate device descriptor on demand for new device */
-                device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
-		if (device == NULL ) {
-			rc = -ENOMEM;
-                        goto out;
-		}
-		memset (device, 0, sizeof (dasd_device_t));
+        dasd_lowmem_t *lowmem;
+        int rc;
+
+
+        /* allocate device descriptor on demand for new device */
+	if (*addr != NULL) { 
+                BUG ();
+        }
+
+        device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
+        if (device == NULL) {
+                return -ENOMEM;
+        }
+        
+        memset (device, 0, sizeof (dasd_device_t));
+        dasd_plug_device (device);
+        device->accessible = 1;
+        INIT_LIST_HEAD (&device->lowmem_pool);
+        
+        /* allocate pages for lowmem pool */
+        for (i = 0; i < DASD_LOWMEM_PAGES; i++) {
+                
+                lowmem = (void *) get_free_page (GFP_ATOMIC|GFP_DMA);
+                if (lowmem == NULL) {
+                        break;
+                }
+
+                list_add (&lowmem->list, &device->lowmem_pool);
+        } 
+
+        if (i < DASD_LOWMEM_PAGES) {
+                /* didn't get the needed lowmem pages */
+                list_for_each_entry (lowmem, &device->lowmem_pool, list) {
+                        MESSAGE (KERN_DEBUG,
+                                 "<devno: %04x> not enough memory - "
+                                 "Free page again :%p",
+                                 devno, lowmem);
+                        free_page ((unsigned long) lowmem);
+                }
+                kfree (device);
+                rc = -ENOMEM;
+        } else {
                 *addr = device;
-                device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA);
-                if (device->lowmem_ccws == NULL) {
-                        rc = -ENOMEM;
-                        goto noccw;
-	}
-#ifdef CONFIG_ARCH_S390X
-                device->lowmem_idals =
-                    device->lowmem_idal_ptr = (void*) get_free_page (GFP_ATOMIC|GFP_DMA);
-                if (device->lowmem_idals == NULL) {
-                        rc = -ENOMEM;
-                        goto noidal;
-                }                
-#endif
-}
-        goto out;
-#ifdef CONFIG_ARCH_S390X
- noidal:
-        free_page ((long) device->lowmem_ccws);
-#endif
- noccw:
-        kfree(device);
- out:
+                rc = 0;
+        }
         return rc;
 }
 
 static inline int
-dasd_state_new_to_del (dasd_device_t **addr )
+dasd_state_new_to_del (dasd_device_t **addr, int devno)
 {
+        dasd_lowmem_t *lowmem;
+
         dasd_device_t *device = *addr;
+
+        /* free private area */
         if (device && device->private) {
                 kfree(device->private);
-                device->private = NULL;
         }
-#ifdef CONFIG_ARCH_S390X
-        free_page ((long)(device->lowmem_idals));
-#endif
-        free_page((long)(device->lowmem_ccws));
+
+        /* free lowmem_pool */
+        list_for_each_entry (lowmem, &device->lowmem_pool, list) {
+                free_page ((unsigned long) lowmem);
+        }
+
+        /* free device */
         kfree(device);
         *addr = NULL; 
         return 0;
 }
 
 static inline int
-dasd_state_new_to_known (dasd_device_t **dptr, int devno, dasd_discipline_t *disc) 
+dasd_state_new_to_known (dasd_device_t **dptr, 
+                         int devno, 
+                         dasd_discipline_t *discipline) 
 {
         int rc = 0;
 	umode_t devfs_perm  = S_IFBLK | S_IRUSR | S_IWUSR;
         struct list_head *l;
-        major_info_t *major_info = NULL;
+        major_info_t *major_info, *tmp;
         int i;
         dasd_device_t *device = *dptr;
         devfs_handle_t dir;
         char buffer[5];
         
-
-	list_for_each (l, &dasd_major_info[0].list) {
-                major_info = list_entry (l, major_info_t, list);
+        major_info = NULL;
+	list_for_each (l, &dasd_major_info) {
+                tmp = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
-			if (major_info->dasd_device[i] == device) {
-				device->kdev = MKDEV (major_info->gendisk.major,
+			if (tmp->dasd_device[i] == device) {
+				device->kdev = MKDEV (tmp->gendisk.major,
                                                       i << DASD_PARTN_BITS);
+                                major_info = tmp;
 				break;
 			}
 		}
-		if (i < DASD_PER_MAJOR) /* we found one */
+		if (major_info != NULL) /* we found one */
 			break;
 	}
-        if ( major_info == NULL || major_info == &dasd_major_info[0] ) 
+        if ( major_info == NULL )
                 BUG();
 
         device->major_info = major_info;
@@ -3192,18 +3964,24 @@
         
         rc = get_dev_info_by_devno (devno, &device->devinfo);
         if ( rc ) {
+                /* returns -EUSERS if boxed !!*/
+                if (rc == -EUSERS) {
+                        device->level = DASD_STATE_BOXED;
+                }
                 goto out;
         }
 
-	DASD_DRIVER_DEBUG_EVENT (5, dasd_state_new_to_known, 
-                                 "got devinfo CU-type %04x and dev-type %04x", 
-                                 device->devinfo.sid_data.cu_type,
-                                 device->devinfo.sid_data.dev_type);
-
+	DBF_EVENT (DBF_NOTICE,
+                   "got devinfo CU-type %04x and dev-type %04x", 
+                   device->devinfo.sid_data.cu_type,
+                   device->devinfo.sid_data.dev_type);
+        
 
         if ( devno != device->devinfo.devno )
                 BUG();
-        device->discipline = dasd_find_disc (device, disc);
+
+        device->discipline = dasd_find_disc (device, 
+                                             discipline);
         if ( device->discipline == NULL ) {
                 rc = -ENODEV;
                 goto out;
@@ -3221,6 +3999,7 @@
                                               MINOR(device->kdev),
                                               devfs_perm,
                                               &dasd_device_operations,NULL);
+        dasd_do_hotplug_event (device, DASD_HOTPLUG_EVENT_ADD);
         device->level = DASD_STATE_KNOWN;
  out:
         return rc;
@@ -3233,7 +4012,7 @@
         /* don't reset to zeros because of persistent data durich detach/attach! */
         devfs_unregister(device->devfs_entry);
         devfs_unregister(device->major_info->gendisk.de_arr[MINOR(device->kdev) >> DASD_PARTN_BITS]);
-
+        dasd_do_hotplug_event (device, DASD_HOTPLUG_EVENT_REMOVE);
         return rc;
 }
 
@@ -3241,12 +4020,21 @@
 dasd_state_known_to_accept (dasd_device_t *device) 
 {
         int rc = 0;
-        device->debug_area = debug_register (device->name, 0, 2, 
-                                             3 * sizeof (long));
-        debug_register_view (device->debug_area, &debug_sprintf_view);
-        debug_register_view (device->debug_area, &debug_hex_ascii_view);
-        DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area created",
-                                 device);
+
+        /* register 'device' debug area, used for all DBF_DEV_XXX calls*/
+        device->debug_area = debug_register (device->name, 
+                                             0,     /* size of debug area */
+                                             2,     /* number of areas */
+                                             8 * sizeof (long));
+
+        debug_register_view (device->debug_area, 
+                             &debug_sprintf_view);
+
+        debug_set_level (device->debug_area, 
+                         DBF_ERR);
+
+        DBF_DEV_EVENT (DBF_EMERG, device, "%s",
+                       "debug area created");
         
         if (device->discipline->int_handler) {
                 rc = s390_request_irq_special (device->devinfo.irq,
@@ -3255,7 +4043,10 @@
                                                0, DASD_NAME,
                                                &device->dev_status);
                 if ( rc ) {
-                        printk("No request IRQ\n");
+
+                        MESSAGE (KERN_DEBUG, "%s",
+                                 "No request IRQ");
+
                         goto out;
                 }
         }
@@ -3272,10 +4063,15 @@
         if (device->discipline->int_handler) {
                 free_irq (device->devinfo.irq, &device->dev_status);
         }
-        DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area deleted",
-                                 device);
-        if ( device->debug_area != NULL )
+
+        DBF_DEV_EVENT (DBF_EMERG, device,
+                       "%p debug area deleted",
+                       device);
+
+        if (device->debug_area != NULL) {
                 debug_unregister (device->debug_area);
+                device->debug_area = NULL;  
+        }
         device->discipline = NULL;
         device->level = DASD_STATE_KNOWN;
  out:
@@ -3297,18 +4093,17 @@
                         s390irq_spin_lock_irqsave (device->devinfo.irq, 
                                                    flags);
                         rc = device->discipline->start_IO (device->init_cqr);
+                        if ( ! rc )
+                        	device->level = DASD_STATE_INIT;
                         s390irq_spin_unlock_irqrestore(device->devinfo.irq, 
                                                        flags);
-                        if ( rc )
-                                goto out;
-                        device->level = DASD_STATE_INIT;
                 } else {
                         rc = -ENOMEM;
                 }
         } else {
                 rc = dasd_state_init_to_ready ( device ); 
         }
- out:
+
         return rc;
 }
 
@@ -3318,15 +4113,8 @@
         int rc = 0;    
         if (device->discipline->do_analysis != NULL)
                 if ( device->discipline->do_analysis (device) == 0 ) 
-                        switch (device->sizes.bp_block) {
-                        case 512:
-                        case 1024:
-                        case 2048:
-                        case 4096:
-                                break;
-                        default:
-                                rc = -EMEDIUMTYPE;
-                        }
+                        rc = dasd_check_bp_block (device);
+        
         if ( device->init_cqr ) {
                 /* This pointer is no longer needed, BUT dont't free the       */ 
                 /* memory, because this is done in bh for finished request!!!! */
@@ -3362,8 +4150,10 @@
 dasd_state_ready_to_online (dasd_device_t *device ) 
 {
         int rc = 0;
-        dasd_unplug_device (device);
-        device->level = DASD_STATE_ONLINE;
+        if (!(rc = dasd_check_bp_block (device))) {
+                dasd_unplug_device (device);
+                device->level = DASD_STATE_ONLINE;
+        }
         return rc;
 }
 
@@ -3383,6 +4173,7 @@
         int i;
         int major = MAJOR(device->kdev);
         int minor = MINOR(device->kdev);
+        request_queue_t *request_queue;
 
         for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
                 if (i == 0)
@@ -3399,11 +4190,16 @@
 		device->major_info->gendisk.part[minor+i].start_sect = 0;
 		device->major_info->gendisk.part[minor+i].nr_sects = 0;
         }
-        device->request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL);
-        device->request_queue->queuedata = device;
-        blk_init_queue (device->request_queue, do_dasd_request);
-        blk_queue_headactive (device->request_queue, 0);
-        elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP);
+
+        request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL);
+        if (request_queue) {
+                request_queue->queuedata = device;
+                blk_init_queue (request_queue, do_dasd_request);
+                blk_queue_headactive (request_queue, 1);
+                elevator_init (&(request_queue->elevator),ELEVATOR_NOOP);
+        }
+        device->request_queue = request_queue;
+        
         return rc;
 }
 
@@ -3424,6 +4220,19 @@
         int i;
         int major = MAJOR(device->kdev);
         int minor = MINOR(device->kdev);
+	request_queue_t *q   = device->request_queue;
+	struct request  *req;
+	long             flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	while (q                           &&
+               !list_empty(&q->queue_head) &&
+               (req = dasd_next_request(q)) != NULL) {
+
+		dasd_end_request(req, 0);
+		dasd_dequeue_request(q, req);
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
         for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
                 destroy_buffers(MKDEV(major,minor+i));
@@ -3453,6 +4262,7 @@
 		       1 << DASD_PARTN_BITS,
 		       &dasd_device_operations,
 		       (device->sizes.blocks << device->sizes.s2b_shift));
+        dasd_do_hotplug_event (device, DASD_HOTPLUG_EVENT_PARTCHK);
 }
 
 static inline void
@@ -3467,14 +4277,7 @@
         }
         devfs_register_partitions(&device->major_info->gendisk,
                                   MINOR(device->kdev),1);
-}
-
-static inline void
-dasd_resetup_partitions ( dasd_device_t * device ) 
-{
-    BUG();
-    dasd_destroy_partitions ( device ) ;
-    dasd_setup_partitions ( device ) ;
+        dasd_do_hotplug_event (device, DASD_HOTPLUG_EVENT_PARTREMOVE);
 }
 
 /*
@@ -3505,11 +4308,11 @@
                 from_state = device->level;
         }
 
-        DASD_DRIVER_DEBUG_EVENT (3, dasd_set_device_level,
-                                 "devno %04x; from %i to %i",
-                                 devno,
-                                 from_state,
-                                 to_state);
+        DBF_EVENT (DBF_INFO,
+                   "devno %04x; from %i to %i",
+                   devno,
+                   from_state,
+                   to_state);
 
         if ( from_state == to_state )
                 goto out;
@@ -3520,20 +4323,30 @@
         /* First check for bringup */
         if ( from_state <= DASD_STATE_DEL &&
              to_state >= DASD_STATE_NEW ) { 
-                rc = dasd_state_del_to_new(device_addr);
+                rc = dasd_state_del_to_new(device_addr, devno);
                 if ( rc ) {
                         goto bringup_fail;
                 }
                 device = *device_addr;
         }
-        if ( from_state <= DASD_STATE_NEW &&
+
+        /* reprobe boxed devices */
+        if (device->level == DASD_STATE_BOXED) {
+                rc = s390_trigger_resense (device->devinfo.irq);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+
+        if ( device->level <= DASD_STATE_BOXED &&
              to_state >= DASD_STATE_KNOWN ) { 
                 rc = dasd_state_new_to_known( device_addr, devno, discipline );
                 if ( rc ) {
                         goto bringup_fail;
                 }
         }
-        if ( from_state <= DASD_STATE_KNOWN &&
+
+        if ( device->level <= DASD_STATE_KNOWN &&
              to_state >= DASD_STATE_ACCEPT ) { 
                 rc = dasd_state_known_to_accept(device);
                 if ( rc ) {
@@ -3543,19 +4356,21 @@
         if ( dasd_probeonly ) {
             goto out;
         }
-        if ( from_state <= DASD_STATE_ACCEPT &&
+
+        if ( device->level <= DASD_STATE_ACCEPT &&
              to_state >= DASD_STATE_INIT ) { 
                 rc = dasd_state_accept_to_init(device);
                 if ( rc ) {
                         goto bringup_fail;
                 }
         }
-        if ( from_state <= DASD_STATE_INIT &&
+        if ( device->level <= DASD_STATE_INIT &&
              to_state >= DASD_STATE_READY ) { 
                 rc = -EAGAIN;
                 goto out;
         }
-        if ( from_state <= DASD_STATE_READY &&
+
+        if ( device->level <= DASD_STATE_READY &&
              to_state >= DASD_STATE_ONLINE ) { 
                 rc = dasd_state_ready_to_online(device);
                 if ( rc ) {
@@ -3564,50 +4379,57 @@
         }
         goto out;
  bringup_fail:   /* revert changes */
-#if 0
-        printk (KERN_DEBUG PRINTK_HEADER
-                "failed to set device from state %d to %d at "
-                "level %d rc %d. Reverting...\n",
-                from_state,
-                to_state,
-                device->level,
-                rc);
-#endif
-        to_state = from_state;
-        from_state = device->level;
+
+        DBF_DEV_EVENT (DBF_ERR, device,
+                       "failed to set device from state %d to %d at "
+                       "level %d rc %d. Reverting...",
+                       from_state,
+                       to_state,
+                       device->level,
+                       rc);
+
+        if (device->level <= DASD_STATE_NEW) {
+                /* Revert - device can not be accessed */
+                to_state = from_state;
+                from_state = device->level;
+        }
         
         /* now do a shutdown */
  shutdown: 
-        if ( from_state >= DASD_STATE_ONLINE &&
+        if ( device->level >= DASD_STATE_ONLINE &&
              to_state <= DASD_STATE_READY ) 
                 if (dasd_state_online_to_ready(device))
                         BUG();
 
-        if ( from_state >= DASD_STATE_READY &&
+        if ( device->level >= DASD_STATE_READY &&
              to_state <= DASD_STATE_ACCEPT ) 
                 if ( dasd_state_ready_to_accept(device))
                         BUG();
 
-        if ( from_state >= DASD_STATE_ACCEPT &&
+        if ( device->level >= DASD_STATE_ACCEPT &&
              to_state <= DASD_STATE_KNOWN ) 
                 if ( dasd_state_accept_to_known(device))
                         BUG();
 
-        if ( from_state >= DASD_STATE_KNOWN &&
+        if ( device->level >= DASD_STATE_KNOWN &&
              to_state <= DASD_STATE_NEW ) 
                 if ( dasd_state_known_to_new(device))
                         BUG();
 
-        if ( from_state >= DASD_STATE_NEW &&
+        if ( device->level >= DASD_STATE_NEW &&
              to_state <= DASD_STATE_DEL) 
-                if (dasd_state_new_to_del(device_addr))
+                if (dasd_state_new_to_del(device_addr, devno))
                         BUG();
         goto out;
  out:
         return rc;
 }
 
-/* SECTION: Procfs stuff */
+/********************************************************************************
+ * SECTION: Procfs stuff 
+ ********************************************************************************/
+#ifdef CONFIG_PROC_FS
+
 typedef struct {
 	char *data;
 	int len;
@@ -3640,29 +4462,53 @@
         int index = 0;
 
         MOD_INC_USE_COUNT;
-        spin_lock_irqsave(&discipline_lock,flags);
+
+        spin_lock_irqsave(&discipline_lock,
+                          flags);
+
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
+
 	if (info == NULL) {
-                printk (KERN_WARNING "No memory available for data\n");
+
+                MESSAGE (KERN_WARNING, "%s",
+                         "No memory available for data (tempinfo)");
+
+                spin_unlock_irqrestore(&discipline_lock,
+                                       flags);
+
                 MOD_DEC_USE_COUNT;
+
                 return -ENOMEM;
+
 	} else {
 		file->private_data = (void *) info;
 	}
-	list_for_each (l, &dasd_major_info[0].list) {
+	list_for_each (l, &dasd_major_info) {
                 size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
 	info->data = (char *) vmalloc (size);	
-	DASD_DRIVER_DEBUG_EVENT (1, dasd_devices_open, "area: %p, size 0x%x",
-				 info->data, 
-                                 size);
+
 	if (size && info->data == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "No memory available for data (info->data)");
+
 		vfree (info);
+
+                spin_unlock_irqrestore(&discipline_lock,
+                                       flags);
+
                 MOD_DEC_USE_COUNT;
+
 		return -ENOMEM;
 	}
-	list_for_each (l, &dasd_major_info[0].list) {
+
+	DBF_EVENT (DBF_NOTICE,
+                   "procfs-area: %p, size 0x%x allocated",
+                   info->data, 
+                   size);
+
+	list_for_each (l, &dasd_major_info) {
 		temp = list_entry (l, major_info_t, list);
 		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
 			dasd_device_t *device;
@@ -3673,8 +4519,8 @@
                                 continue;
 
                         features = dasd_features_from_devno(devno);
-                        if (features < DASD_DEFAULT_FEATURES)
-                                features = DASD_DEFAULT_FEATURES;
+                        if (features < DASD_FEATURE_DEFAULT)
+                                features = DASD_FEATURE_DEFAULT;
 
                         device = temp->dasd_device[i];
 			if (device) {
@@ -3702,45 +4548,45 @@
 					    sprintf (info->data + len,
 						     "detected");
 					break;
+				case DASD_STATE_BOXED:
+					len +=
+					    sprintf (info->data + len,
+						     "boxed");
+					break;
 				case DASD_STATE_ACCEPT:
-                                        len += sprintf (info->data + len,"accepted");
+                                        len += sprintf (info->data + len,
+                                                        "accepted");
 					break;
 				case DASD_STATE_INIT:
-					len +=
-					    sprintf (info->data + len,
-						     "busy   ");
+					len += sprintf (info->data + len,
+                                                        "busy   ");
 					break;
 				case DASD_STATE_READY:
+					len += sprintf (info->data + len,
+							"ready  ");
+					break;
 				case DASD_STATE_ONLINE:
-                                    if ( atomic_read(&device->plugged) )
-                                        len +=
-                                            sprintf (info->data + len,
-                                                     "fenced ");
-                                    else
-                                        len +=
-                                            sprintf (info->data + len,
-                                                     "active ");
-                                    if ( device->sizes.bp_block == 512 ||
-                                         device->sizes.bp_block == 1024 ||
-                                         device->sizes.bp_block == 2048 ||
-                                         device->sizes.bp_block == 4096 )
-					len +=
-					    sprintf (info->data + len,
-						     "at blocksize: %d, %ld blocks, %ld MB",
-						     device->sizes.bp_block,
-						     device->sizes.blocks,
-						     ((device->
-						       sizes.bp_block >> 9) *
-						      device->sizes.
-						      blocks) >> 11);
-                                    else
-                                        len +=
-                                            sprintf (info->data + len,
-                                                     "n/f    ");
+                                        len += sprintf (info->data + len,
+                                                        "active ");
+
+                                        if (dasd_check_bp_block (device))
+                                                len +=
+                                                    sprintf (info->data + len,
+                                                             "n/f    ");
+                                        else
+                                                len +=
+                                                    sprintf (info->data + len,
+                                                             "at blocksize: %d, %ld blocks, %ld MB",
+                                                             device->sizes.bp_block,
+                                                             device->sizes.blocks,
+                                                             ((device->
+                                                               sizes.bp_block >> 9) *
+                                                              device->sizes.
+                                                              blocks) >> 11);
 					break;
 				default:
 					len +=
-					    sprintf (info->data + len,
+                                            sprintf (info->data + len,
 						     "no stat");
 					break;
 				}
@@ -3769,7 +4615,9 @@
                 index += 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
 	info->len = len;
-        spin_unlock_irqrestore(&discipline_lock,flags);
+
+        spin_unlock_irqrestore(&discipline_lock,
+                               flags);
 	return rc;
 }
 
@@ -3793,22 +4641,250 @@
 	}
 }
 
+/* 
+ * scan for device range in given string (e.g. 0x0150-0x0155).
+ * devnos are always hex and leading 0x are ignored.
+ */
+static char *
+dasd_parse_range (char *buffer, dasd_range_t *range)
+{
+        char *str;
+
+        /* remove optional 'device ' and 'range=' and search for nexet digit */
+        for (str = buffer + 4; isspace(*str); str++);
+
+	if (strncmp (str, "device ", 7) == 0) 
+		for (str = str + 7; isspace(*str); str++);
+        
+	if (strncmp (str, "range=", 6) == 0) 
+                for (str = str + 6; isspace(*str); str++);
+        
+        range->to = range->from = dasd_strtoul (str, 
+                                                &str, 
+                                                &(range->features));
+        
+        if (*str == '-') {
+		str++;
+		range->to = dasd_strtoul (str, 
+                                          &str, 
+                                          &(range->features));
+	}
+        
+        /* remove blanks after device range */
+	for (; isspace(*str); str++);
+
+        if (range->from < 0 || range->to < 0) {
+                MESSAGE (KERN_WARNING,
+                         "/proc/dasd/devices: range parse error in '%s'", 
+                         buffer);
+                return ERR_PTR (-EINVAL);
+        }
+
+        return str;
+
+} /* end dasd_parse_range */
+
+/* 
+ * Enable / Disable the given devices  
+ */
+static void
+dasd_proc_set (char *buffer)
+{
+	dasd_range_t range;
+        char *str;
+
+        str = dasd_parse_range (buffer, 
+                                &range);
+        
+        /* Negative numbers in str/from/to indicate errors */
+        if (IS_ERR (str) || (range.from < 0) || (range.to < 0)
+            || (range.from > 65535) || (range.to > 65535)) 
+                return;
+
+        if (strncmp (str, "on", 2) == 0) {
+                dasd_enable_ranges (&range, NULL, 0);
+
+        } else if (strncmp (str, "off", 3) == 0) {
+                dasd_disable_ranges (&range, NULL, 0, 1);
+                
+        } else {
+                MESSAGE (KERN_WARNING,
+                         "/proc/dasd/devices: "
+                         "only 'on' and 'off' are alowed in 'set' "
+                         "command ('%s'/'%s')",
+                         buffer,
+                         str);
+        }
+
+        return;
+
+} /* end dasd_proc_set */
+
+/* 
+ * Add the given devices
+ */
+static void
+dasd_proc_add (char *buffer)
+{
+	dasd_range_t range;
+        char *str;
+        
+        str = dasd_parse_range (buffer, 
+                                &range);
+        
+        /* Negative numbers in str/from/to indicate errors */
+        if (IS_ERR (str) || (range.from < 0) || (range.to < 0)
+            || (range.from > 65535) || (range.to > 65535))
+                return;
+
+        dasd_add_range (range.from, range.to, range.features);
+        dasd_enable_ranges (&range, NULL, 0);
+
+        return;
+
+} /* end dasd_proc_add */
+
+/* 
+ * Break the lock of a given 'boxed' dasd.
+ * If the dasd in not in status 'boxed' just return.  
+ */
+static int
+dasd_break_boxed (dasd_range_t  *range,
+                  dasd_device_t *device)
+{
+        int rc = 0;
+        dasd_discipline_t *discipline;
+        struct list_head  *lh = dasd_disc_head.next;
+                
+        /* check devixe status */
+        if (device->level != DASD_STATE_BOXED) {
+                MESSAGE (KERN_WARNING,
+                         "/proc/dasd/devices: the given device (%04X) "
+                         "is not 'boxed')",
+                         device->devinfo.devno);
+                rc = -EINVAL;
+                goto out; 
+        }
+
+        /* force eckd discipline */
+        do {
+                discipline = list_entry(lh,
+                                        dasd_discipline_t,
+                                        list);
+                
+                if (strncmp (discipline->name, range->discipline, 4) == 0)
+                        break;  /* discipline found */
+                
+                lh = lh->next;    /* check next discipline in list */
+                if (lh == &dasd_disc_head) {
+                        discipline = NULL;
+                        break;
+                }
+        } while ( 1 );
+        device->discipline = discipline;
+
+        if (device->discipline == NULL) {
+                MESSAGE (KERN_WARNING, "%s",
+                         "/proc/dasd/devices: discipline not found "
+                         "in discipline list");
+                rc = -EINVAL;
+                goto out;
+        }
+
+        /* register the int handler to enable IO */
+        rc = s390_request_irq_special (device->devinfo.irq,
+                                       device->discipline->int_handler,
+                                       dasd_not_oper_handler,
+                                       0, 
+                                       DASD_NAME,
+                                       &device->dev_status);
+        if ( rc ) 
+                goto out;
+
+        rc = dasd_steal_lock (device);
+
+        /* unregister the int handler to enable re-sensing */
+        free_irq (device->devinfo.irq, 
+                  &device->dev_status);
+        
+        device->discipline = NULL;
+        device->level      = DASD_STATE_NEW;
+
+ out:
+        return rc;
+
+} /* end dasd_break_boxed */
+
+/* 
+ * Handle the procfs call 'brk <devno> <discipline>.
+ */
+static void
+dasd_proc_brk (char *buffer)
+{
+	char *str;
+	dasd_range_t range;
+        dasd_device_t *device;
+        int rc = 0;
+
+        str = dasd_parse_range (buffer,
+                                 &range);
+
+        if (IS_ERR (str))
+                return;
+
+        if (range.from != range.to) {
+                MESSAGE (KERN_WARNING, "%s",
+                         "/proc/dasd/devices: 'brk <devno> <discipline> "
+                         "is only allowed for a single device (no ranges)");
+                return;
+        }
+
+        /* check for discipline = 'eckd' */
+        if (strncmp(str, "eckd", 4) != 0) {
+                MESSAGE (KERN_WARNING,
+                         "/proc/dasd/devices: 'brk <devno> <discipline> "
+                         "is only allowed for 'eckd' (%s)",
+                         str);
+                return;
+        }
+        
+        memcpy (range.discipline, "ECKD", 4);
+
+	device = *(dasd_device_from_devno (range.from));
+        if (device == NULL) {
+                MESSAGE (KERN_WARNING,
+                         "/proc/dasd/devices: no device found for devno (%04X)",
+                         range.from);
+                return;
+        }
+        
+        rc = dasd_break_boxed (&range, 
+                               device);
+        if (rc == 0) {
+                /* trigger CIO to resense the device */
+                s390_trigger_resense (device->devinfo.irq);
+                
+                // get the device online now
+                dasd_enable_ranges (&range, 
+                                    NULL, 
+                                    0);
+        }
+        
+} /* end dasd_proc_brk */
+
 static ssize_t
 dasd_devices_write (struct file *file, const char *user_buf,
 		    size_t user_len, loff_t * offset)
 {
 	char *buffer;
-	int off = 0;
-	char *temp;
-	dasd_range_t range;
-        int features;
 
 	if (user_len > PAGE_SIZE)
 		return -EINVAL;
-		
+
 	buffer = vmalloc (user_len+1);
 	if (buffer == NULL)
 		return -ENOMEM;
+
 	if (copy_from_user (buffer, user_buf, user_len)) {
 		vfree (buffer);
 		return -EFAULT;
@@ -3821,60 +4897,29 @@
                 buffer[user_len] = '\0';
         }
 
-	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'\n", buffer);
-	if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"/proc/dasd/devices: only 'set' and 'add' are supported verbs\n");
-		return -EINVAL;
-	}
-	off += 4;
-	while (buffer[off] && !isalnum (buffer[off]))
-		off++;
-	if (!strncmp (buffer + off, "device", strlen ("device"))) {
-		off += strlen ("device");
-		while (buffer[off] && !isalnum (buffer[off]))
-			off++;
-	}
-	if (!strncmp (buffer + off, "range=", strlen ("range="))) {
-		off += strlen ("range=");
-		while (buffer[off] && !isalnum (buffer[off]))
-			off++;
-	}
-	
-	temp = buffer + off;
-	range.from = dasd_strtoul (temp, &temp, &features);
-	range.to = range.from;
-
-	if (*temp == '-') {
-		temp++;
-		range.to = dasd_strtoul (temp, &temp, &features);
-	}
+	MESSAGE (KERN_INFO,
+                 "/proc/dasd/devices: '%s'", 
+                 buffer);
+
+	if (strncmp (buffer, "set ", 4) == 0) {
+                /* handle 'set <devno> on/off' */
+                dasd_proc_set (buffer);
+
+        } else if (strncmp (buffer, "add ", 4) == 0) {
+                /* handle 'add <devno>' */
+                dasd_proc_add (buffer);
+
+        } else if (strncmp (buffer, "brk ", 4) == 0) {
+                /* handle 'brk <devno> <discipline>' */
+                dasd_proc_brk (buffer);
 
-        if (range.from == -EINVAL ||
-            range.to   == -EINVAL   ) {
-                
-                printk (KERN_WARNING PRINTK_HEADER
-                        "/proc/dasd/devices: range parse error in '%s'\n", 
-                        buffer);
         } else {
-                off = (long) temp - (long) buffer;
-                if (!strncmp (buffer, "add", strlen ("add"))) {
-                        dasd_add_range (range.from, range.to, features);
-                        dasd_enable_ranges (&range, NULL, 0);
-                } else { 
-                        while (buffer[off] && !isalnum (buffer[off]))
-                                off++;
-                        if (!strncmp (buffer + off, "on", strlen ("on"))) {
-                                dasd_enable_ranges (&range, NULL, 0);
-                        } else if (!strncmp (buffer + off, "off", strlen ("off"))) {
-                                dasd_disable_ranges (&range, NULL, 0, 1);
-                        } else {
-                                printk (KERN_WARNING PRINTK_HEADER
-                                        "/proc/dasd/devices: parse error in '%s'\n",
-                                        buffer);
-                        }
-                }
-        }
+		MESSAGE (KERN_WARNING, "%s",
+                         "/proc/dasd/devices: only 'set' ,'add' and "
+                         "'brk' are supported verbs");
+		vfree (buffer);
+		return -EINVAL;
+	}
 
 	vfree (buffer);
 	return user_len;
@@ -3895,9 +4940,9 @@
 }
 
 static struct file_operations dasd_devices_file_ops = {
-	read:dasd_generic_read,	/* read */
+	read:dasd_generic_read,	        /* read */
 	write:dasd_devices_write,	/* write */
-	open:dasd_devices_open,	/* open */
+	open:dasd_devices_open,	        /* open */
 	release:dasd_devices_close,	/* close */
 };
 
@@ -3914,22 +4959,41 @@
 
         MOD_INC_USE_COUNT;
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
+
 	if (info == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
+ 
+		MESSAGE (KERN_WARNING, "%s",
+                         "No memory available for data (tempinfo)");
+
                 MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 	}
-	info->data = (char *) vmalloc (PAGE_SIZE);	/* FIXME! determine space needed in a better way */
+        /* FIXME! determine space needed in a better way */
+	info->data = (char *) vmalloc (PAGE_SIZE);	
+
 	if (info->data == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "No memory available for data (info->data)");
+
 		vfree (info);
 		file->private_data = NULL;
                 MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
         
+        /* check for active profiling */
+        if (dasd_profile_level == DASD_PROFILE_OFF) {
+
+                info->len = sprintf (info->data, 
+                                     "Statistics are off - they might be "
+                                     "switched on using 'echo set on > "
+                                     "/proc/dasd/statistics'\n");
+                return rc;
+        } 
+
         /* prevent couter 'ouverflow' on output */
 	for (shift = 0, help = dasd_global_profile.dasd_io_reqs;
 	     help > 9999999; help = help >> 1, shift++) ;
@@ -3958,7 +5022,15 @@
 	}
 	len += sprintf (info->data + len, "\n");
 
-	len += sprintf (info->data + len, "Histogram of I/O times (microseconds)\n");
+	for (; i < 32; i++) {
+		len += sprintf (info->data + len, "%7d ",
+                                dasd_global_profile.dasd_io_secs[i] >> shift);
+	}
+	len += sprintf (info->data + len, "\n");
+
+	len += sprintf (info->data + len, 
+                        "Histogram of I/O times (microseconds)\n");
+
 	for (i = 0; i < 16; i++) {
 		len += sprintf (info->data + len, "%7d ",
                                 dasd_global_profile.dasd_io_times[i] >> shift);
@@ -4008,7 +5080,9 @@
 	len += sprintf (info->data + len, "\n");
 
 	len += sprintf (info->data + len,
-                        "Histogram of I/O time between ssch and irq per sector\n");
+                        "Histogram of I/O time between ssch and irq per "
+                        "sector\n");
+
 	for (i = 0; i < 16; i++) {
 		len += sprintf (info->data + len, "%7d ",
                                 dasd_global_profile.dasd_io_time2ps[i] >> shift);
@@ -4064,23 +5138,89 @@
 
 	if (buffer == NULL)
 		return -ENOMEM;
+
 	if (copy_from_user (buffer, user_buf, user_len)) {
 		vfree (buffer);
 		return -EFAULT;
 	}
+
 	buffer[user_len] = 0;
-	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/statictics: '%s'\n",
-		buffer);
-	if (strncmp (buffer, "reset", 4)) {
-		memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
+        
+	MESSAGE (KERN_INFO,
+                 "/proc/dasd/statictics: '%s'",
+                 buffer);
+
+#ifdef DASD_PROFILE
+         /* check for valid verbs */
+	if (strncmp (buffer, "reset", 5) && 
+            strncmp (buffer, "set ",  4)   ) {
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "/proc/dasd/statistics: only 'set' and "
+                         "'reset' are supported verbs");
+
+        	return -EINVAL;
 	}
+
+	if (!strncmp (buffer, "reset", 5)) {
+                
+                /* reset the statistics */
+		memset (&dasd_global_profile, 
+                        0, 
+                        sizeof (dasd_profile_info_t));
+                
+                MESSAGE (KERN_INFO, "%s",
+                         "Statictics reset");
+
+	} else {
+
+                /* 'set xxx' was given */
+                int offset = 4;
+
+                while (buffer[offset] && !isalnum (buffer[offset]))
+                        offset++;
+
+                if (!strncmp (buffer + offset, "on", 2)) {
+                        
+                        /* switch on statistics profiling */
+                        dasd_profile_level = DASD_PROFILE_ON;
+                        
+                        MESSAGE (KERN_INFO, "%s",
+                                 "Statictics switched on");
+                        
+                } else if (!strncmp (buffer + offset, "off", 3)) {
+                        
+                        /* switch off and reset statistics profiling */
+                        memset (&dasd_global_profile, 
+                                0, 
+                                sizeof (dasd_profile_info_t));
+                        
+                        dasd_profile_level = DASD_PROFILE_OFF;
+                        
+                        MESSAGE (KERN_INFO, "%s",
+                                 "Statictics switched off");
+
+                } else {
+
+                        MESSAGE (KERN_WARNING, "%s",
+                                 "/proc/dasd/statistics: only 'set on' and "
+                                 "'set off' are supported verbs");
+                } 
+        } 
+#else
+        MESSAGE (KERN_WARNING, "%s",
+                 "/proc/dasd/statistics: is not activated in this "
+                 "kernel");
+        
+
+#endif /* DASD_PROFILE */
 	return user_len;
 }
 
 static struct file_operations dasd_statistics_file_ops = {
-	read:dasd_generic_read,	/* read */
-	open:dasd_statistics_open,	/* open */
+	read:dasd_generic_read,	        /* read */
 	write:dasd_statistics_write,	/* write */
+	open:dasd_statistics_open,	/* open */
 	release:dasd_devices_close,	/* close */
 };
 
@@ -4113,6 +5253,11 @@
 	remove_proc_entry ("dasd", &proc_root);
 }
 
+#endif /* CONFIG_PROC_FS */
+
+/********************************************************************************
+ * SECTION: Initializing the driver 
+ ********************************************************************************/
 int
 dasd_request_module ( void *name ) {
 	int rc = -ERESTARTSYS;
@@ -4124,16 +5269,17 @@
 	} 
 	while ( (rc=request_module(name)) != 0 ) {
         	DECLARE_WAIT_QUEUE_HEAD(wait);
-		printk ( KERN_INFO "request_module returned %d for %s\n",
+
+		MESSAGE (KERN_INFO,
+                         "request_module returned %d for %s",
                          rc,
                          (char*)name);
+
         	sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */
     	}
     	return rc;
 }
 
-
-/* SECTION: Initializing the driver */
 int __init
 dasd_init (void)
 {
@@ -4142,40 +5288,56 @@
 	major_info_t *major_info = NULL;
 	struct list_head *l;
 
-	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
-	dasd_debug_area = debug_register (DASD_NAME, 0, 2, 5 * sizeof (long));
-	debug_register_view (dasd_debug_area, &debug_sprintf_view);
-	debug_register_view (dasd_debug_area, &debug_hex_ascii_view);
+	MESSAGE (KERN_INFO, "%s",
+                 "initializing...");
 
 	init_waitqueue_head (&dasd_init_waitq);
 
+        /* register 'common' DASD debug area, used faor all DBF_XXX calls*/
+	dasd_debug_area = debug_register (DASD_NAME, 
+                                          0,     /* size of debug area */
+                                          2,     /* number of areas */
+                                          8 * sizeof (long));
+
+	debug_register_view (dasd_debug_area, 
+                             &debug_sprintf_view);
+
 	if (dasd_debug_area == NULL) {
 		goto failed;
 	}
-	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", 
-                                 "ENTRY");
-	dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL);
+
+        debug_set_level (dasd_debug_area, 
+                         DBF_ERR);
+
+        DBF_EVENT (DBF_EMERG, "%s", 
+                   "debug area created");
+
+	dasd_devfs_handle = devfs_mk_dir (NULL, 
+                                          DASD_NAME, 
+                                          NULL);
+
 	if (dasd_devfs_handle < 0) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", 
-                                         "no devfs");
+
+		DBF_EVENT (DBF_ALERT, "%s", 
+                           "no devfs");
 		goto failed;
 	}
-	list_for_each (l, &dasd_major_info[0].list) {
+
+        list_add_tail(&dasd_major_static.list, &dasd_major_info);
+	list_for_each (l, &dasd_major_info) {
 		major_info = list_entry (l, major_info_t, list);
 		if ((rc = dasd_register_major (major_info)) > 0) {
-			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-						 "major %d: success",
-						 major_info->gendisk.major);
-			printk (KERN_INFO PRINTK_HEADER
-				"Registered successfully to major no %u\n",
-				major_info->gendisk.major);
+
+			MESSAGE (KERN_INFO,
+                                 "Registered successfully to major no %u",
+                                 major_info->gendisk.major);
 		} else {
-			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-						 "major %d: failed",
-						 major_info->gendisk.major);
-			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't register successfully to major no %d\n",
-				major_info->gendisk.major);
+
+			MESSAGE (KERN_WARNING,
+                                 "Couldn't register successfully to "
+                                 "major no %d",
+                                 major_info->gendisk.major);
+
 			/* revert registration of major infos */
 			goto failed;
 		}
@@ -4185,18 +5347,24 @@
 #endif				/* ! MODULE */
 	rc = dasd_parse (dasd);
 	if (rc) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s",
-                                         "invalid range found");
+
+		DBF_EVENT (DBF_ALERT, "%s",
+                           "invalid range found");
 		goto failed;
 	}
 
+#ifdef CONFIG_PROC_FS
 	rc = dasd_proc_init ();
 	if (rc) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS");
+                
+		DBF_EVENT (DBF_ALERT, "%s", 
+                           "no proc-FS");
 		goto failed;
 	}
+#endif /* CONFIG_PROC_FS */
+
 	genhd_dasd_name = dasd_device_name;
-	genhd_dasd_ioctl = dasd_ioctl;
+        genhd_dasd_ioctl = dasd_ioctl;
 
 	if (dasd_autodetect) {	/* update device range to all devices */
 		for (irq = get_irq_first (); irq != -ENODEV;
@@ -4204,10 +5372,14 @@
 			int devno = get_devno_by_irq (irq);
 			int index = dasd_devindex_from_devno (devno);
 			if (index == -ENODEV) {	/* not included in ranges */
-				DASD_DRIVER_DEBUG_EVENT (2, dasd_init,
-							 "add %04x to range",
-							 devno);
-				dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+
+				DBF_EVENT (DBF_CRIT,
+                                           "add %04x to range",
+                                           devno);
+
+				dasd_add_range (devno, 
+                                                devno, 
+                                                DASD_FEATURE_DEFAULT);
 			}
 		}
 	}
@@ -4216,15 +5388,15 @@
 #ifdef CONFIG_DASD_DIAG
 		rc = dasd_diag_init ();
 		if (rc == 0) {
-			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-						 "DIAG discipline %s",
-						 "success");
-			printk (KERN_INFO PRINTK_HEADER
-				"Registered DIAG discipline successfully\n");
+
+			MESSAGE (KERN_INFO, "%s",
+                                 "Registered DIAG discipline successfully");
+
 		} else {
-			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-						 "DIAG discipline %s",
-						 "failed");
+
+			DBF_EVENT (DBF_ALERT, "%s",
+                                   "Register DIAG discipline failed");
+
 			goto failed;
 		}
 #endif /* CONFIG_DASD_DIAG */
@@ -4235,13 +5407,14 @@
 #ifdef CONFIG_DASD_ECKD
 	rc = dasd_eckd_init ();
 	if (rc == 0) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-					 "ECKD discipline %s", "success");
-		printk (KERN_INFO PRINTK_HEADER
-			"Registered ECKD discipline successfully\n");
+
+		MESSAGE (KERN_INFO, "%s",
+                         "Registered ECKD discipline successfully");
 	} else {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-					 "ECKD discipline %s", "failed");
+
+		DBF_EVENT (DBF_ALERT, "%s",
+                           "Register ECKD discipline failed");
+
 		goto failed;
 	}
 #endif /* CONFIG_DASD_ECKD */
@@ -4251,14 +5424,14 @@
 #ifdef CONFIG_DASD_FBA
 	rc = dasd_fba_init ();
 	if (rc == 0) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-					 "FBA discipline %s", "success");
-
-		printk (KERN_INFO PRINTK_HEADER
-			"Registered FBA discipline successfully\n");
+                
+		MESSAGE (KERN_INFO, "%s",
+			"Registered FBA discipline successfully");
 	} else {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
-					 "FBA discipline %s", "failed");
+                
+		DBF_EVENT (DBF_ALERT, "%s",
+                           "Register FBA discipline failed");
+
 		goto failed;
 	}
 #endif /* CONFIG_DASD_FBA */
@@ -4276,12 +5449,16 @@
 	rc = 0;
 	goto out;
       failed:
-	printk (KERN_INFO PRINTK_HEADER
-		"initialization not performed due to errors\n");
+
+	MESSAGE (KERN_INFO, "%s",
+                 "initialization not performed due to errors");
+
 	cleanup_dasd ();
       out:
-	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "LEAVE");
-	printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
+        
+	MESSAGE (KERN_INFO, "%s",
+                 "initialization finished");
+
 	return rc;
 }
 
@@ -4293,57 +5470,60 @@
 	struct list_head *l,*n;
 	dasd_range_t *range;
 
-	printk (KERN_INFO PRINTK_HEADER "shutting down\n");
-        DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY");
-	dasd_disable_ranges (&dasd_range_head, NULL, 1, 1);
-        if (MACHINE_IS_VM) {
+	MESSAGE (KERN_INFO, "%s",
+                "shutting down");
+
+	dasd_disable_ranges (&dasd_range_head, 
+                             NULL, 1, 1);
+
 #ifdef CONFIG_DASD_DIAG
+        if (MACHINE_IS_VM) {
                 dasd_diag_cleanup ();
-                DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
-                                         "DIAG discipline %s", "success");
-                printk (KERN_INFO PRINTK_HEADER
-			"De-Registered DIAG discipline successfully\n");
-#endif /* CONFIG_DASD_ECKD_BUILTIN */
+
+                MESSAGE (KERN_INFO, "%s",
+                         "De-Registered DIAG discipline successfully");
 	}
+#endif /* CONFIG_DASD_DIAG */
+
 #ifdef CONFIG_DASD_FBA
 	dasd_fba_cleanup ();
-	DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
-				 "FBA discipline %s", "success");
-	printk (KERN_INFO PRINTK_HEADER
-		"De-Registered FBA discipline successfully\n");
-#endif /* CONFIG_DASD_ECKD_BUILTIN */
+
+	MESSAGE (KERN_INFO, "%s",
+		"De-Registered FBA discipline successfully");
+#endif /* CONFIG_DASD_FBA */
+
 #ifdef CONFIG_DASD_ECKD
 	dasd_eckd_cleanup ();
-	DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
-				 "ECKD discipline %s", "success");
-	printk (KERN_INFO PRINTK_HEADER
-		"De-Registered ECKD discipline successfully\n");
-#endif /* CONFIG_DASD_ECKD_BUILTIN */
 
-	genhd_dasd_name = NULL;
-	genhd_dasd_ioctl = NULL;
+	MESSAGE (KERN_INFO, "%s",
+                 "De-Registered ECKD discipline successfully");
+#endif /* CONFIG_DASD_ECKD */
+
+        genhd_dasd_name = NULL;
+        genhd_dasd_ioctl = NULL;
+
+#ifdef CONFIG_PROC_FS
 	dasd_proc_cleanup ();
+#endif /* CONFIG_PROC_FS */
         
-	list_for_each_safe (l, n, &dasd_major_info[0].list) {
+	list_for_each_safe (l, n, &dasd_major_info) {
 		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			kfree (major_info->dasd_device[i]);
 		}
 		if ((major_info->flags & DASD_MAJOR_INFO_REGISTERED) &&
 		    (rc = dasd_unregister_major (major_info)) == 0) {
-			DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
-						 "major %d: success",
-						 major_info->gendisk.major);
-			printk (KERN_INFO PRINTK_HEADER
-				"Unregistered successfully from major no %u\n",
+
+			MESSAGE (KERN_INFO, 
+				"Unregistered successfully from major no %u",
 				major_info->gendisk.major);
 		} else {
-			DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
-						 "major %d: failed",
-						 major_info->gendisk.major);
-			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't unregister successfully from major no %d rc = %d\n",
-				major_info->gendisk.major, rc);
+
+			MESSAGE (KERN_WARNING,
+                                 "Couldn't unregister successfully from major "
+                                 "no %d rc = %d",
+                                 major_info->gendisk.major, 
+                                 rc);
   		}
   	}
 	list_for_each_safe (l, n, &dasd_range_head.list) {
@@ -4360,10 +5540,14 @@
 #endif /* MODULE */
         if (dasd_devfs_handle) 
                 devfs_unregister(dasd_devfs_handle);
-        if (dasd_debug_area != NULL )
+
+        if (dasd_debug_area != NULL ) {
                 debug_unregister(dasd_debug_area);
-	printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
-        DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
+                dasd_debug_area = NULL;
+        }
+
+	MESSAGE (KERN_INFO, "%s",
+                 "shutdown completed");
 }
 
 #ifdef MODULE

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)