patch-2.4.11-dontuse linux/drivers/s390/s390io.c

Next file: linux/drivers/scsi/3w-xxxx.c
Previous file: linux/drivers/s390/net/netiucv.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.10/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c
@@ -1,12 +1,13 @@
 /*
- *  arch/s390/kernel/s390io.c
+ *  drivers/s390/s390io.c
  *   S/390 common I/O routines
  *
  *  S390 version
  *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
  *                             IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *    ChangeLog: 01/04/2001 Holger Smolinski (smolinsk@de.ibm.com)
+ *    ChangeLog: 01/07/2001 Blacklist cleanup (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *               01/04/2001 Holger Smolinski (smolinsk@de.ibm.com)
  *                          Fixed lost interrupts and do_adapter_IO
  *               xx/xx/xxxx nnn          multiple changes not reflected
  *               03/12/2001 Ingo Adlung  blacklist= - changed to cio_ignore=  
@@ -20,6 +21,9 @@
  *               05/22/2001 Cornelia Huck added /proc/cio_ignore
  *                                        un-ignore blacklisted devices by piping 
  *                                        to /proc/cio_ignore
+ *               xx/xx/xxxx some bugfixes & cleanups
+ *               08/02/2001 Cornelia Huck not already known devices can be blacklisted
+ *                                        by piping to /proc/cio_ignore
  */
 
 #include <linux/module.h>
@@ -29,7 +33,7 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
@@ -50,17 +54,26 @@
 #include <asm/lowcore.h>
 #include <asm/idals.h>
 #include <asm/uaccess.h> 
+#include <asm/cpcmd.h>
 
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
 #include <asm/debug.h>
+#include <asm/queue.h>
 
 #ifndef TRUE
 #define TRUE  1
 #define FALSE 0
 #endif
 
+#define SANITY_CHECK(irq) do { \
+if (irq > highest_subchannel || irq < 0) \
+		return (-ENODEV); \
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) \
+		return (-ENODEV); \
+	} while(0) 
+
 #undef  CONFIG_DEBUG_IO
 #define CONFIG_DEBUG_CRW
 
@@ -129,6 +142,9 @@
 int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
 			     until problems are dealt with */
 
+unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per cpu... */
+int cio_count_irqs = 1;       /* toggle use here... */
+
 /* 
  * "Blacklisting" of certain devices:
  * Device numbers given in the commandline as blacklist=... won't be known to Linux
@@ -139,109 +155,39 @@
  */
 
 typedef struct dev_blacklist_range_t {
+     struct dev_blacklist_range_t *next;  /* next range in list */
      unsigned int from;                   /* beginning of range */
      unsigned int to;                     /* end of range */
-     struct dev_blacklist_range_t *next;  /* next range in list */
+     int  kmalloced;	
+    
 } dev_blacklist_range_t;
 
 static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
+static dev_blacklist_range_t *dev_blacklist_unused_head = NULL;
+
 static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
 static int nr_blacklisted_ranges = 0;
 
 /* Handling of the blacklist ranges */
 
-/* 
- * Function: blacklist_range_create
- * Creates a range from the given parameters
- */
-static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
+static inline void blacklist_range_destroy( dev_blacklist_range_t *range,int locked )
 {
-     dev_blacklist_range_t *range = NULL;
-
-     if (to && (from>to)) {
-	     printk("Invalid blacklist range %x to %x, skipping\n", from, to);
-	     return NULL;
-     }
-     if (init_IRQ_complete) {
-	     range = ( dev_blacklist_range_t *) kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL);
-     } else {
-	     range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
-     }
-     if (range == NULL)
-	  return NULL;
-     memset( range, 0, sizeof( dev_blacklist_range_t ));
-     range->from = from;
-     if (to == 0) {           /* only a single device is given */
-	  range->to = from;
-     } else {
-	  range->to = to;
-     }
-     nr_blacklisted_ranges++;
-     return range;
+	 long flags;
+	 
+	 if(!locked)
+		 spin_lock_irqsave( &blacklist_lock, flags ); 
+	 if(!remove_from_list((list **)&dev_blacklist_range_head,(list *)range))
+		 BUG();
+	 nr_blacklisted_ranges--;
+	 if(range->kmalloced)
+		 kfree(range);
+	 else
+		 add_to_list((list **)&dev_blacklist_unused_head,(list *)range); 
+	 if(!locked)
+		 spin_unlock_irqrestore( &blacklist_lock, flags );
 }
 
-/* 
- * Function: blacklist_range_destroy
- * Free the given range
- */
 
-static inline void blacklist_range_destroy( dev_blacklist_range_t *range )
-{
-	nr_blacklisted_ranges--;
-	/*
-	 * FIXME: the memory was allocated as bootmem, 
-	 * how to get it free again ?! 
-	 */
-	/* kfree( range ); */
-}
-
-/*
- * Function: blacklist_range_append
- * Append a range to the list of blacklisted ranges anchored at dev_blacklist_range_head
- */
-
-static inline void blacklist_range_append( dev_blacklist_range_t *range )
-{
-     dev_blacklist_range_t *temp;
-     long flags;
-
-     spin_lock_irqsave( &blacklist_lock, flags );
-     if (dev_blacklist_range_head == NULL) {
-	  dev_blacklist_range_head = range;
-     } else {
-	  for ( temp = dev_blacklist_range_head;
-		temp && temp->next;
-		temp = temp->next );
-	  temp->next = range;
-     }
-     spin_unlock_irqrestore( &blacklist_lock, flags );
-}
-
-/*
- * Function: blacklist_range_dechain
- * Remove a range from the list of blacklisted ranges
- */
-
-static inline void blacklist_range_dechain( dev_blacklist_range_t *range )
-{
-     dev_blacklist_range_t *temp, *prev = NULL;
-     long flags;
-     
-     spin_lock_irqsave( &blacklist_lock, flags );
-     for ( temp = dev_blacklist_range_head; temp != NULL; temp = temp->next ) {
-	  if ( temp == range )
-	       break;
-	  prev = temp;
-     }
-     if (!temp)
-	  BUG();
-     if (prev) {
-	  prev->next = range->next;
-     } else {
-	  dev_blacklist_range_head = range->next;
-     }
-     spin_unlock_irqrestore( &blacklist_lock, flags );
-}
 
 /* 
  * Function: blacklist_range_add
@@ -249,15 +195,44 @@
  * blacklisted devices
  */
 
-static inline dev_blacklist_range_t *blacklist_range_add( int from, int to )
+static inline dev_blacklist_range_t *blacklist_range_add( int from, int to,int locked)
 {
-     dev_blacklist_range_t *temp;
+ 
+     dev_blacklist_range_t *range = NULL;
+     unsigned long flags;
 
-     temp = blacklist_range_create( from, to );
-     if (!temp) 
-	  return NULL;
-     blacklist_range_append( temp );
-     return temp;
+     if (to && (from>to)) {
+	     printk(KERN_WARNING "Invalid blacklist range %x to %x, skipping\n", from, to);
+	     return NULL;
+     }
+     if(!locked)
+	     spin_lock_irqsave( &blacklist_lock, flags );
+     if(dev_blacklist_unused_head)
+	     range=(dev_blacklist_range_t *)
+		     remove_listhead((list **)&dev_blacklist_unused_head);
+     else if (init_IRQ_complete) {
+	     if((range = ( dev_blacklist_range_t *) 
+		 kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL)))
+		     range->kmalloced=1;
+     } else {
+	     if((range = ( dev_blacklist_range_t *) 
+		 alloc_bootmem( sizeof( dev_blacklist_range_t ) )))
+		     range->kmalloced=0;
+     }
+     if (range)
+     {
+	     add_to_list((list **)&dev_blacklist_range_head,(list *)range);
+	     range->from = from;
+	     if (to == 0) {           /* only a single device is given */
+		     range->to = from;
+	     } else {
+		     range->to = to;
+	     }
+	     nr_blacklisted_ranges++;
+     }
+     if(!locked)
+	     spin_unlock_irqrestore( &blacklist_lock, flags );
+     return range;
 }
 
 /* 
@@ -268,12 +243,14 @@
 static inline void blacklist_range_remove( int from, int to )
 {
      dev_blacklist_range_t *temp;
+     long flags;
 
+     spin_lock_irqsave( &blacklist_lock, flags );
      for ( temp = dev_blacklist_range_head; 
 	   (temp->from != from) && (temp->to != to);
 	   temp = temp->next );
-     blacklist_range_dechain( temp );
-     blacklist_range_destroy( temp );
+     blacklist_range_destroy( temp,1 );
+     spin_unlock_irqrestore( &blacklist_lock, flags );
 }
 
 /* Parsing the commandline for blacklist parameters */
@@ -361,7 +338,7 @@
 	       temp++;
 	       to = blacklist_strtoul( temp, &temp );
 	  }
-	  if (!blacklist_range_add( from, to )) {
+	  if (!blacklist_range_add( from, to,0 )) {
 	       printk( KERN_WARNING "Blacklisting range from %X to %X failed!\n", from, to);
 	  }
 #ifdef CONFIG_DEBUG_IO
@@ -430,20 +407,25 @@
 static inline int is_blacklisted( int devno )
 {
      dev_blacklist_range_t *temp;
+     long flags;
+     int retval=0;
 
      if (dev_blacklist_range_head == NULL) {  
 	  /* no blacklist */
 	  return 0;
      }
 
+     spin_lock_irqsave( &blacklist_lock, flags ); 
      temp = dev_blacklist_range_head;
      while (temp) {
 	  if ((temp->from <= devno) && (temp->to >= devno)) {
-	       return 1;                      /* Deviceno is blacklisted */
+		  retval=1;                      /* Deviceno is blacklisted */
+		  break;
 	  }
 	  temp = temp->next;
      }
-     return 0;
+     spin_unlock_irqrestore( &blacklist_lock, flags );
+     return retval;
 }
 
 /*
@@ -454,12 +436,14 @@
 void blacklist_free_all_ranges(void) 
 {
 	dev_blacklist_range_t *tmp = dev_blacklist_range_head;
+	unsigned long flags;
 
+	spin_lock_irqsave( &blacklist_lock, flags ); 
 	while (tmp) {
-		blacklist_range_dechain(tmp);
-		blacklist_range_destroy(tmp);
+		blacklist_range_destroy(tmp,1);
 		tmp = dev_blacklist_range_head;
 	}
+	spin_unlock_irqrestore( &blacklist_lock, flags );
 }
 
 /*
@@ -477,6 +461,8 @@
 	int to = 0;
 	int changed = 0;
 	dev_blacklist_range_t *range, *temp;
+	long flags;
+	int err = 0;
 
 	tmp = buf;
 	if (strstr(tmp, "free ")) {
@@ -506,39 +492,97 @@
 				} else {
 					to = from;
 				}
+				spin_lock_irqsave( &blacklist_lock, flags ); 
 				range = dev_blacklist_range_head;
 				while (range != NULL) {
 					temp = range->next;
 					if ((from <= range->from) && (to >= range->to)) {
-						blacklist_range_dechain(range);
-						blacklist_range_destroy(range);
+						blacklist_range_destroy(range,1);
 						changed = 1;
 					} else if ((from <= range->from) && (to>=range->from) && (to < range->to)) {
-						blacklist_range_add(to+1, range->to);
-						blacklist_range_dechain(range);
-						blacklist_range_destroy(range);
+						blacklist_range_add(to+1, range->to,1);
+						blacklist_range_destroy(range,1);
 						changed = 1;
 					} else if ((from > range->from) && (from<=range->to) && (to >= range->to)) {
-						blacklist_range_add(range->from, from-1);
-						blacklist_range_dechain(range);
-						blacklist_range_destroy(range);
+						blacklist_range_add(range->from, from-1,1);
+						blacklist_range_destroy(range,1);
 						changed = 1;
 					} else if ((from > range->from) && (to < range->to)) {
-						blacklist_range_add(range->from, from-1);
-						blacklist_range_add(to+1, range->to);
-						blacklist_range_dechain(range);
-						blacklist_range_destroy(range);
+						blacklist_range_add(range->from, from-1,1);
+						blacklist_range_add(to+1, range->to,1);
+						blacklist_range_destroy(range,1);
 						changed = 1;
 					}
 					range = temp;
 				}
+				spin_unlock_irqrestore( &blacklist_lock, flags );
 				kfree(param);
 			}
 			if (changed)
 				s390_redo_validation();
 		}
+	} else if (strstr(tmp, "add ")) {
+		for (i=0;i<4;i++){
+			tmp++;
+		}
+		while (tmp != NULL) {
+			end = strchr(tmp, ',');
+			if (end == NULL) {
+				len = strlen(tmp) + 1;
+			} else {
+				len = (long)end - (long) tmp + 1;
+				*end = '\0';
+				end++;
+			}
+			param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
+			strncpy(param, (const char *) tmp, len);
+			tmp = end;
+			from = blacklist_strtoul(param, &param);
+			if (*param == '-') {
+				param++;
+				to = blacklist_strtoul(param, &param);
+			} else {
+				to = from;
+			}
+			spin_lock_irqsave( &blacklist_lock, flags ); 
+			
+			/*
+			 * Don't allow for already known devices to be
+			 * blacklisted
+			 * The criterion is a bit dumb, devices which once were
+			 * there but are already gone are also caught...
+			 */
+			
+			err = 0;
+			for (i=0; i<=highest_subchannel; i++) {
+				if (ioinfo[i]!=INVALID_STORAGE_AREA) {
+					if (   (ioinfo[i]->schib.pmcw.dev >= from)
+					    && (ioinfo[i]->schib.pmcw.dev <= to)  ) {
+						printk(KERN_WARNING "cio_ignore: Won't blacklist "
+						       "already known devices, skipping range "
+						       "%x to %x\n", from, to);
+						err = 1;
+						break;
+					}
+				}
+			}
+
+			/*
+			 * Note: We allow for overlapping ranges here, 
+			 * since the user might specify overlapping ranges
+			 * and we walk through all ranges when freeing anyway.
+			 */
+
+			if (!err) 
+				blacklist_range_add(from, to, 1);
+			
+			spin_unlock_irqrestore( &blacklist_lock, flags );
+			kfree(param);
+		}
+
 	} else {
 		printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
+		printk("or 'add <devno-range>,<devno-range>,...'\n");
 	}
 }
 
@@ -571,17 +615,19 @@
 {
 	s32 cnt1, cnt2, maxcnt2;
 	u32 *currptr = (__u32 *)ptr;
+	char buffer[cnt*12];
 
 	debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
 
 	for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
-		debug_sprintf_event(cio_debug_msg_id, level, "%08lX ", (unsigned long)currptr);
+		sprintf(buffer, "%08lX ", (unsigned long)currptr);
 		maxcnt2 = cnt - cnt1;
 		if (maxcnt2 > 16)
 			maxcnt2 = 16;
 		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
-			debug_sprintf_event(cio_debug_msg_id, level, "%08X ", *currptr++);
+			sprintf(buffer, "%08X ", *currptr++);
 	}
+	debug_sprintf_event(cio_debug_msg_id, level, "%s\n",buffer);
 }
 
 static int __init cio_setup( char *parm )
@@ -704,6 +750,10 @@
 	return;  	
 }
 
+/*
+ * Note : internal use of irqflags SA_PROBE for NOT path grouping 
+ *
+ */
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -714,6 +764,7 @@
 	int		retval = 0;
 	unsigned long	flags;
 	char            dbf_txt[15];
+	int             retry;
 
 	if (irq >= __MAX_SUBCHANNELS)
 		return -EINVAL;
@@ -738,12 +789,28 @@
 
 	if ( !ioinfo[irq]->ui.flags.ready )
 	{
+		retry = 5;
+		
 		ioinfo[irq]->irq_desc.handler = io_handler;
 		ioinfo[irq]->irq_desc.name    = devname;
 		ioinfo[irq]->irq_desc.dev_id  = dev_id;
 		ioinfo[irq]->ui.flags.ready   = 1;
+		
+		
+		do {
+			retval = enable_subchannel(irq);
+			if (retval) {
+				ioinfo[irq]->ui.flags.ready = 0;
+				break;
+			}
+			
+			stsch(irq,&ioinfo[irq]->schib);
+			if (ioinfo[irq]->schib.pmcw.ena) 
+				retry = 0;
+			else
+				retry--;
 
-		enable_subchannel(irq);
+		} while (retry);
 	}
 	else
 	{
@@ -761,7 +828,8 @@
 
 	if ( retval == 0 )
 	{
-		s390_DevicePathVerification( irq, 0 );
+		if ( !(irqflags & SA_PROBE))
+			s390_DevicePathVerification( irq, 0 );
 
 		ioinfo[irq]->ui.flags.newreq = 1;
 		ioinfo[irq]->nopfunc         = not_oper_handler;  	
@@ -838,6 +906,15 @@
 			/* start deregister */
 			ioinfo[irq]->ui.flags.unready = 1;
 
+			/*
+			 * Try to stop IO first...
+			 * ... it seems disable_subchannel is sometimes
+			 * successfully called with IO still pending.
+			 */
+			halt_IO( irq,
+				 0xC8C1D3E3,
+				 DOIO_WAIT_FOR_INTERRUPT );
+
 			do
 			{
 				ret = disable_subchannel( irq);
@@ -888,23 +965,23 @@
 					} /* endif */
 
 					if ( count == 2 )
-               {
+					{
 						/* give it a very last try ... */
 						disable_subchannel( irq);
 
 						if ( ioinfo[irq]->ui.flags.busy )
-					   {
+					        {
 							printk( KERN_CRIT"free_irq(%04X) "
 							       "- device %04X busy, retry "
 							       "count exceeded\n",
-						   	    irq,
-						      	 ioinfo[irq]->devstat.devno);
+								irq,
+								ioinfo[irq]->devstat.devno);
 							if (cio_debug_initialized)
 								debug_sprintf_event(cio_debug_msg_id, 0,
 										    "free_irq(%04X) - device %04X busy, retry count exceeded\n",
 										    irq, ioinfo[irq]->devstat.devno);
 
-                  } /* endif */
+						} /* endif */
 						
 						break; /* sigh, let's give up ... */
 
@@ -957,8 +1034,7 @@
 	int           ret;
 	char dbf_txt[15];
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-		return( -ENODEV);
+	SANITY_CHECK(irq);
 
 	if ( !ioinfo[irq]->ui.flags.ready )
 		return -ENODEV;
@@ -984,8 +1060,7 @@
 	int           ret;
 	char dbf_txt[15];
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-		return( -ENODEV);
+	SANITY_CHECK(irq);
 
 	if ( !ioinfo[irq]->ui.flags.ready )
 		return -ENODEV;
@@ -1008,19 +1083,12 @@
  */
 static int enable_subchannel( unsigned int irq)
 {
-	int   ret;
+	int   ret = 0;
 	int   ccode;
 	int   retry = 5;
 	char dbf_txt[15];
 
-	if ( irq > highest_subchannel || irq < 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-		return( -ENODEV);
+	SANITY_CHECK(irq);
 
 	if (cio_debug_initialized) {
 		debug_text_event(cio_debug_trace_id, 2, "ensch");
@@ -1064,19 +1132,12 @@
 				ccode = msch( irq, &(ioinfo[irq]->schib) );
 
 				switch (ccode) {
-				case 0:
+				case 0: /* ok */
 					ret = 0;
+					retry = 0;
 					break;
 
-				case 1:
-					/*
-					 * very bad, requires interrupt alike
-					 *  processing, where "rbh" is a dummy
-					 *  parameter for interface compatibility
-					 *  only. Bottom-half handling cannot be
-					 *  required as this must be an
-					 *  unsolicited interrupt (!busy).
-					 */
+				case 1: /* status pending */
 
 					ioinfo[irq]->ui.flags.s_pend = 1;
 					s390_process_IRQ( irq );
@@ -1084,36 +1145,24 @@
 
 					ret = -EIO;    /* might be overwritten */
 					               /* ... on re-driving    */
-					               /* ... the msch() */
+					               /* ... the msch()       */
 					retry--;
 					break;
 
-				case 2:
+				case 2: /* busy */
 					udelay(100);	/* allow for recovery */
 					ret = -EBUSY;
 					retry--;
 					break;
 
-				case 3:
+				case 3: /* not oper */
 					ioinfo[irq]->ui.flags.oper = 0;
+					retry = 0;
 					ret = -ENODEV;
 					break;
-
-				default:
-					printk( KERN_CRIT"enable_subchannel(%04X) "
-					        " : ccode 2 on msch() for device "
-					        "%04X received !\n",
-					        irq,
-					        ioinfo[irq]->devstat.devno);
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 0,
-								    "enable_subchannel(%04X) : ccode 2 on msch() for device %04X received !\n",
-								    irq, ioinfo[irq]->devstat.devno);
-
-					ret = -ENODEV; // never reached
 				}
 
-			} while ( (ccode == 1) && retry );
+			} while ( retry );
 
 		} /* endif */
 
@@ -1129,19 +1178,13 @@
 static int disable_subchannel( unsigned int irq)
 {
 	int  cc;          /* condition code */
-	int  ret;         /* function return value */
+	int  ret = 0;     /* function return value */
 	int  retry = 5;
 	char dbf_txt[15];
 
-	if ( irq > highest_subchannel )
-	{
-		ret = -ENODEV;
-	}
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-	}
-	else if ( ioinfo[irq]->ui.flags.busy )
+	SANITY_CHECK(irq);
+	
+	if ( ioinfo[irq]->ui.flags.busy )
 	{
 		/*
 		 * the disable function must not be called while there are
@@ -1180,19 +1223,12 @@
 				cc = msch( irq, &(ioinfo[irq]->schib) );
 
 				switch (cc) {
-				case 0 :
-					ret = 0;   /* done */
+				case 0: /* ok */
+					retry = 0;
+					ret = 0;   
 					break;
 
-				case 1 :
-					/*
-					 * very bad, requires interrupt alike
-  					 *  processing, where "rbh" is a dummy
-					 *  parm for interface compatibility
-					 *  only. Bottom-half handling cannot
-					 *  be required as this must be an
-					 *  unsolicited interrupt (!busy).
-					 */
+				case 1: /* status pending */
 					ioinfo[irq]->ui.flags.s_pend = 1;
 					s390_process_IRQ( irq );
 					ioinfo[irq]->ui.flags.s_pend = 0;
@@ -1203,45 +1239,36 @@
 					retry--;
 					break;
 
-				case 2 :
-					/*
-					 * *** must not occur !              ***
-					 * ***                               ***
-					 * *** indicates our internal        ***
-					 * *** interrupt accounting is out   ***
-					 * ***  of sync ===> panic()         ***
-					 */
+				case 2: /* busy; this should not happen! */
 					printk( KERN_CRIT"disable_subchannel(%04X) "
 					        "- unexpected busy condition for "
-							  "device %04X received !\n",
+						"device %04X received !\n",
 					        irq,
 					        ioinfo[irq]->devstat.devno);
 					if (cio_debug_initialized)
 						debug_sprintf_event(cio_debug_msg_id, 0, 
 								    "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
 								    irq, ioinfo[irq]->devstat.devno);
+					retry = 0;
 					ret = -EBUSY;
 					break;
 
-				case 3 :
+				case 3: /* not oper */
 					/*
 					 * should hardly occur ?!
 					 */
 					ioinfo[irq]->ui.flags.oper      = 0;
 					ioinfo[irq]->ui.flags.d_disable = 1;
+					retry = 0;
 
 					ret = 0; /* if the device has gone we */
 					         /* ... don't need to disable */
-					         /* ... it anymore !    */
-					break;
-
-				default :
-					ret = -ENODEV;  // never reached ...
+					         /* ... it anymore !          */
 					break;
 
 				} /* endswitch */
 
-			} while ( (cc == 1) && retry );
+			} while ( retry );
 
 		} /* endif */
 
@@ -1282,6 +1309,12 @@
 
 	s390_process_subchannels();
 
+	if (cio_count_irqs) {
+		int i;
+		for (i=0; i<NR_CPUS; i++) 
+			s390_irq_count[i]=0;
+	}
+
 	/*
 	 * enable default I/O-interrupt sublass 3
 	 */
@@ -1318,6 +1351,8 @@
 	char buffer[80];
 	char dbf_txt[15];
 
+	SANITY_CHECK(irq);
+
 	/*
 	 * The flag usage is mutal exclusive ...
 	 */
@@ -1804,16 +1839,7 @@
 	int ret = 0;
 	char dbf_txt[15];
 
-	if ( irq > highest_subchannel || irq < 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
+	SANITY_CHECK(irq);
 
 	/* handler registered ? or free_irq() in process already ? */
 	if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
@@ -1848,7 +1874,7 @@
 		 *  but its intparm must be returned (see halt_IO() processing)
 		 */
 		if (     ioinfo[irq]->ui.flags.w4final
-           && !ioinfo[irq]->ui.flags.doio_q )
+		      && !ioinfo[irq]->ui.flags.doio_q )
 		{
 			ioinfo[irq]->qflag    = flag;
 			ioinfo[irq]->qcpa     = cpa;
@@ -1879,16 +1905,7 @@
 	int ret = 0;
 	char dbf_txt[15];
 
-	if ( irq > highest_subchannel || irq < 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-	}
+	SANITY_CHECK(irq);
 
 	if (cio_debug_initialized) {
 		debug_text_event(cio_debug_trace_id, 4, "resIO");
@@ -1954,20 +1971,12 @@
 	int            ccode;
 	char dbf_txt[15];
 
-	if ( irq > highest_subchannel || irq < 0 )
-	{
-		return -ENODEV;
-	}
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-	}
+	SANITY_CHECK(irq);
 
 	/*
 	 * we only allow for halt_IO if the device has an I/O handler associated
 	 */
-	else if ( !ioinfo[irq]->ui.flags.ready )
+	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 		ret = -ENODEV;
 	}
@@ -1979,6 +1988,7 @@
 	{
 		ret = 0;
 	}
+#if 0
 	/*
 	 * We don't allow for halt_io with a sync do_IO() requests pending.
 	 */
@@ -1987,6 +1997,7 @@
 	{
 		ret = -EBUSY;
 	}
+#endif
 	else
 	{
 		if (cio_debug_initialized) {
@@ -2141,7 +2152,7 @@
 			 * Let the common interrupt handler process the pending
 			 *  status. However, we must avoid calling the user
 			 *  action handler, as it won't be prepared to handle
-                        *  a pending status during do_IO() processing inline.
+			 *  a pending status during do_IO() processing inline.
 			 *  This also implies that s390_process_IRQ must
 			 *  terminate synchronously - especially if device
 			 *  sensing is required.
@@ -2216,14 +2227,11 @@
               unsigned long user_intparm,
               unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
 {
-	int            ret;
+	int            ret = 0;
 	int            ccode;
 	char dbf_txt[15];
 
-	if ( irq > highest_subchannel || irq < 0 )
-	{
-		return -ENODEV;
-	}
+	SANITY_CHECK(irq);
 
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
@@ -2231,22 +2239,23 @@
    }
 
 	/*
-	 * we only allow for halt_IO if the device has an I/O handler associated
+	 * we only allow for clear_IO if the device has an I/O handler associated
 	 */
-	else if ( !ioinfo[irq]->ui.flags.ready )
+	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 		ret = -ENODEV;
 	}
 	/*
-	 * we ignore the halt_io() request if ending_status was received but
+	 * we ignore the clear_io() request if ending_status was received but
 	 *  a SENSE operation is waiting for completion.
 	 */
 	else if ( ioinfo[irq]->ui.flags.w4sense )
 	{
 		ret = 0;
 	}
+#if 0
 	/*
-	 * We don't allow for halt_io with a sync do_IO() requests pending.
+	 * We don't allow for clear_io with a sync do_IO() requests pending.
 	 *  Concurrent I/O is possible in SMP environments only, but the
 	 *  sync. I/O request can be gated to one CPU at a time only.
 	 */
@@ -2254,6 +2263,7 @@
 	{
 		ret = -EBUSY;
 	}
+#endif
 	else
 	{
 		if (cio_debug_initialized) {
@@ -2280,7 +2290,7 @@
 		} /* endif */
 
 		/*
-		 * Issue "Halt subchannel" and process condition code
+		 * Issue "Clear subchannel" and process condition code
 		 */
 		ccode = csch( irq );
 
@@ -2361,7 +2371,7 @@
 					                    | _PSW_IO_WAIT;
 					break;
 				default:
-					panic( "halt_IO() : unexpected "
+					panic( "clear_IO() : unexpected "
 					       "address-space-control %d\n",
 					       ccode);
 					break;
@@ -2394,65 +2404,13 @@
 			ret = 0;
 			break;
 
-		case 1 :            /* status pending */
-
-			ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
-			/*
-			 * initialize the device driver specific devstat irb area
-			 */
-			memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb,
-			        '\0', sizeof( irb_t) );
-
-			/*
-			 * Let the common interrupt handler process the pending
-			 *  status. However, we must avoid calling the user
-			 *  action handler, as it won't be prepared to handle
-                        *  a pending status during do_IO() processing inline.
-			 *  This also implies that s390_process_IRQ must
-			 *  terminate synchronously - especially if device
-			 *  sensing is required.
-			 */
-			ioinfo[irq]->ui.flags.s_pend   = 1;
-			ioinfo[irq]->ui.flags.busy     = 1;
-			ioinfo[irq]->ui.flags.doio     = 1;
-
-			s390_process_IRQ( irq );
-			
-			ioinfo[irq]->ui.flags.s_pend   = 0;
-			ioinfo[irq]->ui.flags.busy     = 0;
-			ioinfo[irq]->ui.flags.doio     = 0;
-			ioinfo[irq]->ui.flags.repall   = 0;
-			ioinfo[irq]->ui.flags.w4final  = 0;
-
-			ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
-
-			/*
-			 * In multipath mode a condition code 3 implies the last
-			 *  path has gone, except we have previously restricted
-			 *  the I/O to a particular path. A condition code 1
-			 *  (0 won't occur) results in return code EIO as well
-			 *  as 3 with another path than the one used (i.e. path available mask is non-zero).
-			 */
-			if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 0;
-			}
-			else
-			{
-				ret                         = -EIO;
-				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 1;
-
-			} /* endif */ 
-
+		case 1 :            /* no status pending for csh */
+			BUG();
 			break;
 
-		case 2 :            /* busy */
 
-			ret = -EBUSY;
+		case 2 :            /* no busy for csh*/
+			BUG();
 			break;
 
 		default:            /* device not operational */
@@ -2572,7 +2530,6 @@
 	unsigned int           fctl;       /* function control */
 	unsigned int           stctl;      /* status   control */
 	unsigned int           actl;       /* activity control */
-	struct pt_regs         regs;       /* for interface compatibility only */
 
 	int               issense         = 0;
 	int               ending_status   = 0;
@@ -2582,11 +2539,15 @@
 	devstat_t        *udp;
 
 	char dbf_txt[15];
-#if 0
-	int               cpu             = smp_processor_id();
+	char buffer[80];
 
-	kstat.irqs[cpu][irq]++;
-#endif
+
+	if (cio_count_irqs) {
+		int cpu = smp_processor_id();
+		s390_irq_count[cpu]++;
+	}
+	
+	
 
 	if (cio_debug_initialized) {
 		debug_text_event(cio_debug_trace_id, 3, "procIRQ");
@@ -2688,9 +2649,28 @@
 	 *  secondary status are presented with different interrupts.
 	 */
 	if ( dp->ii.irb.scsw.stctl
-	           & (   SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) )
-	{
-		dp->rescnt = dp->ii.irb.scsw.count;
+	     & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) ) {
+
+		/*
+		 * If the subchannel status shows status pending
+		 * and we received a check condition, the count
+		 * information is not meaningful.
+		 */
+		
+		 if ( !(    (dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND) 
+			 && (   dp->ii.irb.scsw.cstat 
+			      & (   SCHN_STAT_CHN_DATA_CHK
+				  | SCHN_STAT_CHN_CTRL_CHK
+				  | SCHN_STAT_INTF_CTRL_CHK
+				  | SCHN_STAT_PROG_CHECK
+				  | SCHN_STAT_PROT_CHECK
+				  | SCHN_STAT_CHAIN_CHECK )))) {
+
+			 dp->rescnt = dp->ii.irb.scsw.count;
+		 } else {
+			 dp->rescnt = SENSE_MAX_COUNT;
+		 }
+
 		dp->cpa    = dp->ii.irb.scsw.cpa;
 
 #ifdef CONFIG_DEBUG_IO
@@ -2743,13 +2723,13 @@
 		issense=0;
 	}
 	else if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
-	     &&	(dp->ii.irb.scsw.eswf  == 0                     ))
+	          && (dp->ii.irb.scsw.eswf  == 0                     ))
 	{
 		issense = 0;
 	}
-	else if (    (dp->ii.irb.scsw.stctl ==
-	                (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
-	          && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0))
+	else if (   (dp->ii.irb.scsw.stctl ==
+		      (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
+		 && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)  )
 	{
 		issense = 0;
 	}
@@ -2797,8 +2777,6 @@
 
 		if ( chnchk )
 		{
-			char buffer[80];
-   	
 			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
 			         "device %04X after channel check\n",
 			         irq,
@@ -2824,8 +2802,8 @@
 
 		ending_status =    ( stctl & SCSW_STCTL_SEC_STATUS                          )
 			|| ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)         )
-		   || ( (fctl == SCSW_FCTL_HALT_FUNC)  && (stctl == SCSW_STCTL_STATUS_PEND) )
-		   || ( (fctl == SCSW_FCTL_CLEAR_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) );
+			|| ( (fctl == SCSW_FCTL_HALT_FUNC)  && (stctl == SCSW_STCTL_STATUS_PEND) )
+			|| ( (fctl == SCSW_FCTL_CLEAR_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) );
 
 		/*
 		 * Check for unsolicited interrupts - for debug purposes only
@@ -2838,10 +2816,9 @@
 		 *       unsolicited interrupt applies to the console device
 		 *       itself !
 		 */
-		if ( !( stctl & SCSW_STCTL_ALERT_STATUS )
-		     &&  ( ioinfo[irq]->ui.flags.busy == 0  ) )
+		if (    !( stctl & SCSW_STCTL_ALERT_STATUS )
+		     &&  ( ioinfo[irq]->ui.flags.busy == 0 ) )
 		{
-			char buffer[80];
 #ifdef CONFIG_DEBUG_IO
 			if (irq != cons_dev)
 				printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
@@ -2895,7 +2872,7 @@
 		 *       violates the ESA/390 architecture and doesn't present an
 		 *       operand exception for virtual devices without concurrent
 		 *       sense facility available/supported when enabling the
-       *       concurrent sense facility.
+		 *       concurrent sense facility.
 		 */
 		if (    (    (dp->ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
 		          && (!issense                                    ) )
@@ -2992,8 +2969,8 @@
 		if ( allow4handler )
 		{
 			allow4handler =    ending_status
-			   || ( ioinfo[irq]->ui.flags.repall                                      )
-			   || ( stctl & SCSW_STCTL_INTER_STATUS                                   )
+				|| ( ioinfo[irq]->ui.flags.repall                                      )
+				|| ( stctl & SCSW_STCTL_INTER_STATUS                                   )
 				|| ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
 				|| ( ioinfo[irq]->ui.flags.oper == 0                                   );
 
@@ -3041,20 +3018,10 @@
 				}
 				else
 				{
-#if 1
 					panic( "s390_process_IRQ(%04x) encountered "
 					       "negative sense count\n",
 					       irq);
-#else
-					printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
-					        "negative sense count\n",
-					        irq);
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 0,
-								    "s390_process_IRQ(%04x) encountered "
-								    "negative sense count\n",
-								    irq);		    
-#endif
+
 				} /* endif */
 			}
 			else
@@ -3063,7 +3030,7 @@
 
 			}  /* endif */
 
-      } /* endif */
+		} /* endif */
 
 		/*
 		 * for status pending situations other than deferred interrupt
@@ -3118,7 +3085,7 @@
 				dp->flag  |= DEVSTAT_FINAL_STATUS;
 				udp->flag |= DEVSTAT_FINAL_STATUS;
 
-				ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
+				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
 
 				//
 				// reset intparm after final status or we will badly present unsolicited
@@ -3150,7 +3117,7 @@
 					 */
 					if ( ret )
 					{
-						ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
+						ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
 
 					} /* endif */
 
@@ -3178,7 +3145,7 @@
 
 				} /* endif */
 
-				ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
+				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
 
 			} /* endif */
 
@@ -3261,7 +3228,7 @@
 
 		if ( !ioinfo[irq]->ui.flags.s_pend )
 		{
-			ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
+			ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
 
 		} /* endif */
 
@@ -3298,18 +3265,12 @@
 	int           rc = 0;
 	char dbf_txt[15];
 
+	SANITY_CHECK(irq);
+
 	if ( cons_dev != -1  )
 	{
 		rc = -EBUSY;
 	}
-	else if ( (irq > highest_subchannel) || (irq < 0) )
-	{
-		rc = -ENODEV;
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
 	else
 	{
 		if (cio_debug_initialized) {
@@ -3366,18 +3327,12 @@
 	long    cr6 __attribute__ ((aligned (8)));
 	char dbf_txt[15];
 
+	SANITY_CHECK(irq);
+
 	if ( cons_dev != -1  )
 	{
 		rc = -EBUSY;
 	}
-	else if ( (irq > highest_subchannel) || (irq < 0) )
-	{
-		rc = -ENODEV;
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
 	else
 	{
 		if (cio_debug_initialized) {
@@ -3496,7 +3451,7 @@
 	int             ccode;
 	long            cr6 __attribute__ ((aligned (8)));
 
-	int             count = 0;
+	int             retry = 3;
 	int             rc    = 0;
 	char dbf_txt[15];
 
@@ -3538,48 +3493,44 @@
 					ccode = msch( irq,
 					              &(ioinfo[irq]->schib) );
 
-					if (ccode == 0 )
-					{
+					switch (ccode) {
+					case 0: 
 						/*
 						 * enable special isc
 						 */
-					__ctl_store( cr6, 6, 6);
-					cr6 |= 0x04000000;  // enable sync isc 5
-					cr6 &= 0xEFFFFFFF;  // disable standard isc 3
-					__ctl_load( cr6, 6, 6);
-					}
-					else if (ccode == 3)
-					{
-						rc = -ENODEV;  // very unlikely
-
-					}
-					else if (ccode == 2)
-					{
-						rc = -EBUSY; // device busy ...
-
-					}
-					else if (ccode == 1)
-					{
+						__ctl_store( cr6, 6, 6);
+						cr6 |= 0x04000000;  // enable sync isc 5
+						cr6 &= 0xEFFFFFFF;  // disable standard isc 3
+						__ctl_load( cr6, 6, 6);
+						retry = 0;
+						break;
+					
+					case 1:
 						//
 						// process pending status
 						//
 						ioinfo[irq]->ui.flags.s_pend = 1;
-
 						s390_process_IRQ( irq );
-
 						ioinfo[irq]->ui.flags.s_pend = 0;
+						
+						rc = -EIO;  /* might be overwritten... */
+						retry--;
+						break;
 
-						count++;
+					case 2: /* busy */
+						retry = 0;
+						rc = -EBUSY; 
+						break;
 
-					} /* endif */
+					case 3: /* not oper*/
+						retry = 0;
+						rc = -ENODEV; 
+						break;
+					
+					}
 
-				} while ( ccode == 1 && count < 3 );
+				} while ( retry );
 
-				if ( count == 3)
-				{
-					rc = -EIO;
-                       	
-				} /* endif */
 			}
 			else
 			{
@@ -3651,6 +3602,7 @@
 
 			do
 			{
+			        retry2 = 5;
 				do
 				{
 					ccode = msch( irq, &(ioinfo[irq]->schib) );
@@ -3660,27 +3612,33 @@
 						/*
 						 * disable special interrupt subclass in CPU
 						 */
-				__ctl_store( cr6, 6, 6);
-				cr6 &= 0xFBFFFFFF; // disable sync isc 5
-				cr6 |= 0x10000000; // enable standard isc 3
-				__ctl_load( cr6, 6, 6);
+						__ctl_store( cr6, 6, 6);
+						cr6 &= 0xFBFFFFFF; // disable sync isc 5
+						cr6 |= 0x10000000; // enable standard isc 3
+						__ctl_load( cr6, 6, 6);
+
+						retry2 = 0;
 						break;
-					case 1:
+
+					case 1: /* status pending */
 						ioinfo[irq]->ui.flags.s_pend = 1;
 						s390_process_IRQ( irq );
 						ioinfo[irq]->ui.flags.s_pend = 0;
+
 						retry2--;
 						break;
-					case 2:
+
+					case 2: /* busy */
 					        retry2--;
 						udelay( 100); // give it time
 						break;
-					default:
+						
+					default: /* not oper */
 						retry2 = 0;
 						break;
 					} /* endswitch */
 
-				} while ( retry2 && (ccode != 0) );
+				} while ( retry2 );
 
 				retry1--;
 
@@ -4073,7 +4031,7 @@
 	ccw1_t       *rdc_ccw;
 	devstat_t     devstat;
 	char         *rdc_buf;
-	int           devflag;
+	int           devflag = 0;
 
 	int           ret      = 0;
 	int           emulated = 0;
@@ -4087,15 +4045,7 @@
 
 	} /* endif */
 
-	if ( (irq > highest_subchannel) || (irq < 0 ) )
-	{
-	return( -ENODEV );
-
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-	}
+	SANITY_CHECK(irq);
 
 	if ( ioinfo[irq]->ui.flags.oper == 0 )
 	{
@@ -4126,7 +4076,7 @@
 	{
 		ret = request_irq( irq,
 		                   init_IRQ_handler,
-		                   0, "RDC", &devstat );
+		                   SA_PROBE, "RDC", &devstat );
 
 		if ( !ret )
 		{
@@ -4159,22 +4109,27 @@
 				rdc_ccw->cmd_code = CCW_CMD_RDC;
 				rdc_ccw->count    = length;
 				rdc_ccw->flags    = CCW_FLAG_SLI;
-				set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
+				ret = set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
+				if (!ret) {
 
-				memset( ioinfo[irq]->irq_desc.dev_id,
-				        '\0',
-				        sizeof( devstat_t));
+					memset( ioinfo[irq]->irq_desc.dev_id,
+						'\0',
+						sizeof( devstat_t));
 
-				ret = s390_start_IO( irq,
-				                     rdc_ccw,
-				                     0x00524443, // RDC
-				                     0,          // n/a
-				                     DOIO_WAIT_FOR_INTERRUPT
-				                      | DOIO_DONT_CALL_INTHDLR );
-				retry--;
-				devflag = ioinfo[irq]->irq_desc.dev_id->flag;   
-    
-				clear_normalized_cda( rdc_ccw);  
+					ret = s390_start_IO( irq,
+							     rdc_ccw,
+							     0x00524443, // RDC
+							     0,          // n/a
+							     DOIO_WAIT_FOR_INTERRUPT
+							     | DOIO_DONT_CALL_INTHDLR );
+					retry--;
+					devflag = ioinfo[irq]->irq_desc.dev_id->flag;   
+					
+					clear_normalized_cda( rdc_ccw);  
+				} else {
+					udelay(100);  //wait for recovery
+					retry--;
+				}
 
 			} while (    ( retry                                     )
 			          && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
@@ -4183,7 +4138,7 @@
 
 		if ( !retry )
 		{
-			ret = -EBUSY;
+			ret = (ret==-ENOMEM)?-ENOMEM:-EBUSY;
 
 		} /* endif */
 
@@ -4222,15 +4177,9 @@
 
 	char dbf_txt[15];
 
-	if ( (irq > highest_subchannel) || (irq < 0 ) )
-	{
-		return( -ENODEV );
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-	}
-	else if ( !buffer || !length )
+	SANITY_CHECK(irq);
+
+	if ( !buffer || !length )
 	{
 		return( -EINVAL);
 	}
@@ -4267,11 +4216,11 @@
 
 			} /* endif */
 
-      	break;
+			break;
 
-      } /* endif */
+		} /* endif */
 
-   } /* endfor */
+	} /* endfor */
 
 	if ( found )
 	{
@@ -4292,7 +4241,7 @@
 			pdevstat = &devstat;
 			ret      = request_irq( irq,
 			                        init_IRQ_handler,
-			                        0, "RCD", pdevstat );
+			                        SA_PROBE, "RCD", pdevstat );
 
 			if ( !ret )
 			{
@@ -4358,30 +4307,29 @@
 					                     0x00524344,  // == RCD
 					                     lpm,
 					                     ioflags );
+					switch ( ret ) {
+					case 0:
+					case -EIO:
+						
+						if ( !(pdevstat->flag & (   DEVSTAT_STATUS_PENDING
+									    | DEVSTAT_NOT_OPER
+									    | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
+						{
+							retry = 0;  // we got it ...
+						}
+						else
+						{
+							retry--;    // try again ...
+								
+						} /* endif */
+						
+						break;
 
-	            switch ( ret ) {
-   	         case 0    :
-      	      case -EIO :
-
-	               if ( !(pdevstat->flag & (   DEVSTAT_STATUS_PENDING
-   	                                      | DEVSTAT_NOT_OPER
-      	                                   | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
-	               {
-   	               retry = 0;  // we got it ...
-      	         }
-         	      else
-            	   {
-               	   retry--;    // try again ...
-
-	               } /* endif */
-
-   	            break;
-
-	            default :   // -EBUSY, -ENODEV, ???
-   	            retry = 0;
-
-      	      } /* endswitch */
-
+					default:   // -EBUSY, -ENODEV, ???
+						retry = 0;
+						
+					} /* endswitch */
+					
 				} while ( retry );
 
 			} /* endif */
@@ -4440,31 +4388,16 @@
 
 static int __inline__ get_next_available_irq( ioinfo_t *pi)
 {
-	int ret_val;
+	int ret_val = -ENODEV;
 
-	while ( TRUE )
-	{
-		if ( pi->ui.flags.oper )
-		{
+	while ( pi!=NULL ) {
+		if ( pi->ui.flags.oper ) {
 			ret_val = pi->irq;
 			break;
-		}
-		else
-		{
+		} else {
 			pi = pi->next;
-
-			//
-			// leave at end of list unconditionally
-			//
-			if ( pi == NULL )
-			{
-				ret_val = -ENODEV;
-				break;
-			}
-
-		} /* endif */
-
-	} /* endwhile */
+		}
+	}
 
 	return ret_val;
 }
@@ -4536,54 +4469,44 @@
 int get_dev_info_by_irq( int irq, s390_dev_info_t *pdi)
 {
 
-	if ( irq > highest_subchannel || irq < 0 )
-	{
-		return -ENODEV;
-	}
-	else if ( pdi == NULL )
-	{
+	SANITY_CHECK(irq);
+
+	if ( pdi == NULL )
 		return -EINVAL;
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+
+	pdi->devno = ioinfo[irq]->schib.pmcw.dev;
+	pdi->irq   = irq;
+	
+	if (   ioinfo[irq]->ui.flags.oper
+	    && !ioinfo[irq]->ui.flags.unknown ) 
 	{
-		return( -ENODEV);
+		pdi->status = 0;
+		memcpy( &(pdi->sid_data),
+			&ioinfo[irq]->senseid,
+			sizeof( senseid_t));
+	}
+	else if ( ioinfo[irq]->ui.flags.unknown )
+	{
+		pdi->status = DEVSTAT_UNKNOWN_DEV;
+		memset( &(pdi->sid_data),
+			'\0',
+			sizeof( senseid_t));
+		pdi->sid_data.cu_type = 0xFFFF;
+			
 	}
 	else
 	{
-		pdi->devno = ioinfo[irq]->schib.pmcw.dev;
-		pdi->irq   = irq;
-
-		if (     ioinfo[irq]->ui.flags.oper
-           && !ioinfo[irq]->ui.flags.unknown )
-		{
-			pdi->status = 0;
-			memcpy( &(pdi->sid_data),
-			        &ioinfo[irq]->senseid,
-			        sizeof( senseid_t));
-		}
-		else if ( ioinfo[irq]->ui.flags.unknown )
-		{
-			pdi->status = DEVSTAT_UNKNOWN_DEV;
-			memset( &(pdi->sid_data),
-			        '\0',
-			        sizeof( senseid_t));
-			pdi->sid_data.cu_type = 0xFFFF;
-
-		}
-		else
-		{
-			pdi->status = DEVSTAT_NOT_OPER;
-			memset( &(pdi->sid_data),
-			        '\0',
-			        sizeof( senseid_t));
-			pdi->sid_data.cu_type = 0xFFFF;
-
-		} /* endif */
-
-		if ( ioinfo[irq]->ui.flags.ready )
-			pdi->status |= DEVSTAT_DEVICE_OWNED;
-
+		pdi->status = DEVSTAT_NOT_OPER;
+		memset( &(pdi->sid_data),
+			'\0',
+			sizeof( senseid_t));
+		pdi->sid_data.cu_type = 0xFFFF;
+		
 	} /* endif */
+	
+	if ( ioinfo[irq]->ui.flags.ready )
+		pdi->status |= DEVSTAT_DEVICE_OWNED;
+
 
 	return 0;
 }
@@ -4595,70 +4518,60 @@
 	int rc = -ENODEV;
 
 	if ( devno > 0x0000ffff )
-	{
 		return -ENODEV;
-	}
-	else if ( pdi == NULL )
-	{
+        if ( pdi == NULL )
 		return -EINVAL;
-	}
-	else
-	{
 
-		for ( i=0; i <= highest_subchannel; i++ )
+	for ( i=0; i <= highest_subchannel; i++ ) {
+		
+		if (    ioinfo[i] != INVALID_STORAGE_AREA
+		     && ioinfo[i]->schib.pmcw.dev == devno )
 		{
-
-			if (    ioinfo[i] != INVALID_STORAGE_AREA
-			     && ioinfo[i]->schib.pmcw.dev == devno )
+			
+			pdi->irq   = i;
+			pdi->devno = devno;
+			
+			if (    ioinfo[i]->ui.flags.oper
+			     && !ioinfo[i]->ui.flags.unknown )
 			{
+				pdi->status = 0;
+				memcpy( &(pdi->sid_data),
+					&ioinfo[i]->senseid,
+					sizeof( senseid_t));
+			}
+			else if ( ioinfo[i]->ui.flags.unknown )
+			{
+				pdi->status = DEVSTAT_UNKNOWN_DEV;
 
-				pdi->irq   = i;
-				pdi->devno = devno;
-
-				if (    ioinfo[i]->ui.flags.oper
-                 && !ioinfo[i]->ui.flags.unknown )
-				{
-					pdi->status = 0;
-
-					memcpy( &(pdi->sid_data),
-					        &ioinfo[i]->senseid,
-					        sizeof( senseid_t));
-				}
-				else if ( ioinfo[i]->ui.flags.unknown )
-				{
-					pdi->status = DEVSTAT_UNKNOWN_DEV;
-
-					memset( &(pdi->sid_data),
-                       '\0',
-                       sizeof( senseid_t));
-
-					pdi->sid_data.cu_type = 0xFFFF;
-				}
-				else
-				{
-					pdi->status = DEVSTAT_NOT_OPER;
-	
-					memset( &(pdi->sid_data),
-                       '\0',
-                       sizeof( senseid_t));
+				memset( &(pdi->sid_data),
+					'\0',
+					sizeof( senseid_t));
 
-					pdi->sid_data.cu_type = 0xFFFF;
+				pdi->sid_data.cu_type = 0xFFFF;
+			}
+			else
+			{
+				pdi->status = DEVSTAT_NOT_OPER;
+				
+				memset( &(pdi->sid_data),
+					'\0',
+					sizeof( senseid_t));
 
-				} /* endif */
+				pdi->sid_data.cu_type = 0xFFFF;
 
-				if ( ioinfo[i]->ui.flags.ready )
-					pdi->status |= DEVSTAT_DEVICE_OWNED;
+			} /* endif */
 
-				rc = 0; /* found */
-				break;
+			if ( ioinfo[i]->ui.flags.ready )
+				pdi->status |= DEVSTAT_DEVICE_OWNED;
 
-			} /* endif */
+			rc = 0; /* found */
+			break;
 
-		} /* endfor */
+		} /* endif */
 
-		return( rc);
+	} /* endfor */
 
-	} /* endif */
+	return( rc);
 
 }
 
@@ -4742,7 +4655,7 @@
 
 		irq_ret = request_irq( irq,
 		                       init_IRQ_handler,
-		                       0,
+		                       SA_PROBE,
 		                       "INIT",
 		                       &devstat);
 
@@ -4804,7 +4717,6 @@
 					
 				} /* endif */
 #endif
-				s390_DevicePathVerification( irq, 0 );
 
 				disable_cpu_sync_isc( irq );
 
@@ -5040,8 +4952,8 @@
 				{
 					ioinfo_t *pi = ioinfo_head;
 
-					do
-					{
+					for (pi=ioinfo_head; pi!=NULL; pi=pi->next) {
+
 						if ( irq < pi->next->irq )
 						{
 							ioinfo[irq]->next = pi->next;
@@ -5051,11 +4963,7 @@
 							break;
 						
 						} /* endif */
-
-						pi = pi->next;
-
-					} while ( 1 );
-      	
+					}
 				} /* endif */
 
 			} /* endif */
@@ -5303,20 +5211,13 @@
 	int        io_retry;      /* retry indicator */
 
 	senseid_t *psid     = sid;/* start with the external buffer */	
-	int        sbuffer  = 0; /* switch SID data buffer */
+	int        sbuffer  = 0;  /* switch SID data buffer */
 
 	char dbf_txt[15];
 
-	if ( (irq > highest_subchannel) || (irq < 0 ) )
-	{
-		return( -ENODEV );
-
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
+	int failure = 0;          /* nothing went wrong yet */
 
-	} /* endif */
+	SANITY_CHECK(irq);
 
 	if ( ioinfo[irq]->ui.flags.oper == 0 )
 	{
@@ -5330,6 +5231,8 @@
 		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
+	inlreq = 0; /* to make the compiler quiet... */
+
 	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 
@@ -5341,7 +5244,7 @@
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
+		irq_ret = request_irq( irq, init_IRQ_handler, SA_PROBE, "SID", &devstat);
 
 		if ( irq_ret == 0 )
 			inlreq = 1;
@@ -5403,6 +5306,9 @@
 
 			if ( domask )
 			{
+				failure = 0;
+				
+				psid->reserved   = 0;
 				psid->cu_type    = 0xFFFF;  /* initialize fields ... */
 				psid->cu_model   = 0;
 				psid->dev_type   = 0;
@@ -5423,23 +5329,18 @@
 					irq_ret = s390_start_IO( irq,
 					                         sense_ccw,
 					                         0x00E2C9C4,  // == SID
-			   		                      domask,
+								 domask,
 					                         DOIO_WAIT_FOR_INTERRUPT
 					                          | DOIO_TIMEOUT
 					                          | DOIO_VALID_LPM
 					                          | DOIO_DONT_CALL_INTHDLR );
 
-					//
-					// The OSA_E FE card possibly causes -ETIMEDOUT
-					//  conditions, as the SenseID may stay start
-					//  pending. This will cause start_IO() to finally
-					//  halt the operation we should retry. If the halt
-					//  fails this may cause -EBUSY we simply retry
-					//  and eventually clean up with free_irq().   	     		
-					//
 
 					if ( psid->cu_type  == 0xFFFF )
 					{
+
+						failure = 1;
+
 						if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
 						{
 #ifdef CONFIG_DEBUG_IO
@@ -5448,7 +5349,7 @@
 							        "reports pending status, "
 							        "retry : %d\n",
 							        ioinfo[irq]->schib.pmcw.dev,
-					   		     irq,
+								irq,
 							        retry);
 #endif
 							if (cio_debug_initialized)
@@ -5487,7 +5388,7 @@
 											    "intervention required\n",
 											    ioinfo[irq]->schib.pmcw.dev,
 											    irq);		    
-								io_retry = 1;
+								io_retry = 0;
 							}
 
 							else
@@ -5514,7 +5415,7 @@
 								        pdevstat->ii.sense.data[6],
 								        pdevstat->ii.sense.data[7]);
 #endif
-								if (cio_debug_initialized)
+								if (cio_debug_initialized) {
 									debug_sprintf_event(cio_debug_msg_id, 2,
 											    "SenseID : UC on "
 											    "dev %04X, "
@@ -5536,11 +5437,16 @@
 											    pdevstat->ii.sense.data[5],
 											    pdevstat->ii.sense.data[6],
 											    pdevstat->ii.sense.data[7]);	    
+									if (psid->reserved != 0xFF) 
+										debug_sprintf_event(cio_debug_msg_id, 2,
+												    "SenseID was not properly "
+												    "executed!\n");
+								}
 							} /* endif */
 
 						}
 						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
-					             || ( irq_ret        == -ENODEV         ) )
+							  || ( irq_ret        == -ENODEV         ) )
 						{
 #ifdef CONFIG_DEBUG_IO
 							printk( "SenseID : path %02X for "
@@ -5566,11 +5472,11 @@
       	
 						}
 
-						else if (     (pdevstat->flag !=
-						                    (   DEVSTAT_START_FUNCTION
-						                      | DEVSTAT_FINAL_STATUS    ) )
-						           && !(pdevstat->flag &
-						                    DEVSTAT_STATUS_PENDING        ) )
+						else if (     ( pdevstat->flag !=
+							       (   DEVSTAT_START_FUNCTION
+								 | DEVSTAT_FINAL_STATUS    ) )
+							   && !( pdevstat->flag &
+								DEVSTAT_STATUS_PENDING       ) )
 						{
 #ifdef CONFIG_DEBUG_IO
 							printk( "SenseID : start_IO() for "
@@ -5602,45 +5508,54 @@
 					}
 					else   // we got it ...
 					{
-						if ( !sbuffer )	// switch buffers
-						{
-							/*
-							 * we report back the
-							 *  first hit only
-							 */
-							psid = &isid;
+						if (psid->reserved != 0xFF) {
+							/* No, we failed after all... */
+							failure = 1;
+							retry--;
 
-							if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-							{
-								sense_ccw[1].cda = (__u32)virt_to_phys( psid );
-							}
-							else
+						} else {
+					       
+							if ( !sbuffer )	// switch buffers
 							{
-								sense_ccw[0].cda = (__u32)virt_to_phys( psid );
-
+								/*
+								 * we report back the
+								 *  first hit only
+								 */
+								psid = &isid;
+								
+								if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
+								{
+									sense_ccw[1].cda = (__u32)virt_to_phys( psid );
+								}
+								else
+								{
+									sense_ccw[0].cda = (__u32)virt_to_phys( psid );
+
+								} /* endif */
+
+								/*
+								 * if just the very first
+								 *  was requested to be
+								 *  sensed disable further
+								 *  scans.
+								 */	
+								if ( !lpm )
+									lpm = domask;
+								
+								sbuffer = 1;
+								
 							} /* endif */
 
-							/*
-							 * if just the very first
-							 *  was requested to be
-							 *  sensed disable further
-							 *  scans.
-							 */	
-							if ( !lpm )
-								lpm = domask;
-
-							sbuffer = 1;
-
-						} /* endif */
-
-					   if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
-						{
-							ioinfo[irq]->ui.flags.esid = 1;
+							if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
+							{
+								ioinfo[irq]->ui.flags.esid = 1;
        							
-						} /* endif */
+							} /* endif */
 
-						io_retry = 0;
+							io_retry = 0;
 						
+						}
+
 					} /* endif */
 
 					if ( io_retry )
@@ -5654,7 +5569,19 @@
 						} /* endif */
       	
 					} /* endif */
-	
+
+					if ((failure) && (io_retry)) {
+						/* reset fields... */
+
+						failure = 0;
+						
+						psid->reserved   = 0;
+						psid->cu_type    = 0xFFFF;  
+						psid->cu_model   = 0;
+						psid->dev_type   = 0;
+						psid->dev_model  = 0;
+					}
+						
 				} while ( (io_retry) );
 
  			} /* endif - domask */
@@ -5685,7 +5612,7 @@
 		 *  only if we suffered a command reject, but it doesn't harm
 		 */
 		if (    ( sid->cu_type == 0xFFFF    )
-		     && ( MACHINE_IS_VM              ) )
+		     && ( MACHINE_IS_VM             ) )
 		{
 			VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
 			                        sid );
@@ -5715,9 +5642,9 @@
 		} /* endif */
 
 	
-			/*
-			 * Issue device info message if unit was operational .
-			 */
+		/*
+		 * Issue device info message if unit was operational .
+		 */
 		if ( !ioinfo[irq]->ui.flags.unknown ) {
 			if ( sid->dev_type != 0 ) {
 				if ( cio_show_msg ) 
@@ -5791,10 +5718,11 @@
  *  available. Further, a path group ID is set, if possible in multipath
  *  mode, otherwise in single path mode.
  *
+ * Note : This function must not be called during normal device recognition,
+ *         but during device driver initiated request_irq() processing only.
  */
 int s390_DevicePathVerification( int irq, __u8 usermask )
 {
-#if 1
 	int  ccode;
 	__u8 pathmask;
 	__u8 domask;
@@ -5971,9 +5899,7 @@
 	} /* endif */
 
 	return ret;
-#else
-	return 0;
-#endif
+
 }
 
 /*
@@ -5995,16 +5921,7 @@
 	int        inlreq  = 0; /* inline request_irq() */
 	int        mpath   = 1; /* try multi-path first */
 
-	if ( (irq > highest_subchannel) || (irq < 0 ) )
-	{
-		return( -ENODEV );
-
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-
-	} /* endif */
+	SANITY_CHECK(irq);
 
 	if ( ioinfo[irq]->ui.flags.oper == 0 )
 	{
@@ -6015,14 +5932,14 @@
 	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 		/*
-		 * Perform SENSE ID command processing. We have to request device
+		 * Perform SetPGID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
 		irq_ret = request_irq( irq,
 		                       init_IRQ_handler,
-		                       0,
+		                       SA_PROBE,
 		                       "SPID",
 		                       pdevstat);
 
@@ -6062,7 +5979,7 @@
 		pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
 
 		/*
-		 * We now issue a SenseID request. In case of BUSY
+		 * We now issue a SetPGID request. In case of BUSY
 		 *  or STATUS PENDING conditions we retry 5 times.
 		 */
 		do
@@ -6099,12 +6016,15 @@
 								    ioinfo[irq]->schib.pmcw.dev,
 								    irq,
 								    retry);	    
+					retry--;
+					irq_ret = -EIO;
 				} /* endif */
 
 				if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
 				                         | DEVSTAT_FINAL_STATUS   ) )
 				{
 					retry = 0;	// successfully set ...
+					irq_ret = 0;
 				}
 				else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
 				{
@@ -6121,6 +6041,7 @@
 							               | SPID_FUNC_ESTABLISH;
 							mpath        = 0;
 							retry--;
+							irq_ret = -EIO;
 						}
 						else
 						{
@@ -6170,6 +6091,7 @@
 									    pdevstat->ii.sense.data[7]);
 
 						retry--;
+						irq_ret = -EIO;
 		    
 					} /* endif */
 
@@ -6201,20 +6123,17 @@
 			else if ( irq_ret != -ENODEV )
 			{
 				retry--;
+				irq_ret = -EIO;
 			}
 			else
 			{
 				retry = 0;
+				irq_ret = -ENODEV;
 
 			} /* endif */
 
 		} while ( retry > 0 );
 
-		if ( retry == 0 )
-		{
-			irq_ret = -EIO;
-
-		} /* endif */
 
 		if ( init_IRQ_complete )
 		{
@@ -6256,17 +6175,9 @@
 	int        irq_ret = 0; /* return code */
 	int        retry   = 5; /* retry count */
 	int        inlreq  = 0; /* inline request_irq() */
+	unsigned long flags;
 
-	if ( (irq > highest_subchannel) || (irq < 0 ) )
-	{
-		return( -ENODEV );
-
-	}
-	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-
-	} /* endif */
+	SANITY_CHECK(irq);
 
 	if ( ioinfo[irq]->ui.flags.oper == 0 )
 	{
@@ -6277,14 +6188,14 @@
 	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 		/*
-		 * Perform SENSE ID command processing. We have to request device
+		 * Perform SENSE PGID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
 		irq_ret = request_irq( irq,
 		                       init_IRQ_handler,
-		                       0,
+		                       SA_PROBE,
 		                       "SNID",
 		                       pdevstat);
 
@@ -6300,7 +6211,7 @@
 
 	if ( irq_ret == 0 )
 	{
-		s390irq_spin_lock( irq);
+		s390irq_spin_lock_irqsave( irq, flags);
 
 		if ( init_IRQ_complete )
 		{
@@ -6318,7 +6229,7 @@
 		snid_ccw->flags    = CCW_FLAG_SLI;
 
 		/*
-		 * We now issue a SenseID request. In case of BUSY
+		 * We now issue a SensePGID request. In case of BUSY
 		 *  or STATUS PENDING conditions we retry 5 times.
 		 */
 		do
@@ -6391,6 +6302,7 @@
 									    pdevstat->ii.sense.data[6],
 									    pdevstat->ii.sense.data[7]);		    
 						retry--;
+						irq_ret = -EIO;
 
 					} /* endif */
 				}
@@ -6413,11 +6325,13 @@
 					}
 
 					retry = 0;
+					irq_ret = -EIO;
 
 				}
 				else
 				{
 					retry = 0; // success ...
+					irq_ret = 0;
 
 				} /* endif */
 			}
@@ -6458,20 +6372,17 @@
 							    ioinfo[irq]->schib.pmcw.dev,
 							    irq_ret);
 				retry--;
+				irq_ret = -EIO;
 			}
 			else	// -ENODEV ...
 			{
 				retry = 0;
+				irq_ret = -ENODEV;
 
 			} /* endif */
 
 		} while ( retry > 0 );
 
-		if ( retry == 0 )
-		{
-			irq_ret = -EIO;
-
-		} /* endif */
 
 		if ( init_IRQ_complete )
 		{
@@ -6483,7 +6394,7 @@
 
 		} /* endif */
 
-		s390irq_spin_unlock( irq);
+		s390irq_spin_unlock_irqrestore( irq, flags);
 
 		/*
 		 * If we installed the irq action handler we have to
@@ -6585,12 +6496,25 @@
 			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
 			{
 #ifdef CONFIG_DEBUG_CRW
-				printk( "do_crw_pending : ioinfo at %08X\n",
+				printk( "do_crw_pending : ioinfo at "
+#ifdef CONFIG_ARCH_S390X
+					"%08lX\n",
+					(unsigned long)ioinfo[irq]);
+#else /* CONFIG_ARCH_S390X */
+					"%08X\n",
 				        (unsigned)ioinfo[irq]);
+#endif /* CONFIG_ARCH_S390X */
 #endif
 				if (cio_debug_initialized)
 					debug_sprintf_event(cio_debug_crw_id, 4,
-							    "ioinfo at %08X\n");
+							    "ioinfo at "
+#ifdef CONFIG_ARCH_S390X
+							    "%08lX\n",
+							    (unsigned long)ioinfo[irq]);
+#else /* CONFIG_ARCH_S390X */
+				                            "%08X\n",
+							    (unsigned)ioinfo[irq]);
+#endif /* CONFIG_ARCH_S390X */
 			} /* endif */
 
 
@@ -6892,7 +6816,7 @@
 				    ioinfo[i]->senseid.cu_model );
 	       } else {
 		    len += sprintf( info->data+len, 
-				    "%04X/%02X          ", 
+				    "          %04X/%02X", 
 				    ioinfo[i]->senseid.cu_type, 
 				    ioinfo[i]->senseid.cu_model );
 	       }
@@ -7034,30 +6958,6 @@
      }
 }
 
-int cio_search_devno_by_inode(struct inode *inode)
-{
-	int devno = -1;
-	struct proc_dir_entry *pde;
-	cio_procfs_device_t *tmp;
-	
-	pde = (struct proc_dir_entry *)inode->u.generic_ip;
-	tmp = cio_procfs_device_list;
-
-	while (tmp) {
-		if ((tmp->entry->cio_device_entry == pde) ||
-		    (tmp->entry->cio_sensedata_entry == pde) ||
-		    (tmp->entry->cio_in_use_entry == pde) ||
-		    (tmp->entry->cio_chpid_entry == pde))
-			break;
-		tmp = tmp->next;
-	}
-
-	if (tmp)
-		devno = tmp->entry->devno;
-		
-	return devno;
-}
-
 
 static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
 {
@@ -7067,6 +6967,7 @@
 	tempinfo_t *info;
 	int irq;
 	int devno;
+	char * devno_str;
 
 	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
 	if (info == NULL) {
@@ -7081,23 +6982,24 @@
 			vfree(info);
 			rc = -ENOMEM;
 		} else {
-			devno = cio_search_devno_by_inode(inode);
-			if (devno != 0xFFFF) {
-				irq = get_irq_by_devno(devno);
-				if (irq != -1) {
-					len += sprintf(info->data+len, "Dev Type/Mod: ");
-					if (ioinfo[irq]->senseid.dev_type == 0) {
-						len += sprintf(info->data+len, "%04X/%02X\n",
-							       ioinfo[irq]->senseid.cu_type,
-							       ioinfo[irq]->senseid.cu_model);
-					} else {
-						len += sprintf(info->data+len, "%04X/%02X\n",
-							       ioinfo[irq]->senseid.dev_type,
-							       ioinfo[irq]->senseid.dev_model);
-						len+= sprintf(info->data+len, "CU Type/Mod:  %04X/%02X\n",
-							      ioinfo[irq]->senseid.cu_type,
-							      ioinfo[irq]->senseid.cu_model);
-					}
+			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
+			memset(devno_str, 0, 6*sizeof(char));
+			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
+			devno = simple_strtoul(devno_str, &devno_str, 16);
+			irq = get_irq_by_devno(devno);
+			if (irq != -1) {
+				len += sprintf(info->data+len, "Dev Type/Mod: ");
+				if (ioinfo[irq]->senseid.dev_type == 0) {
+					len += sprintf(info->data+len, "%04X/%02X\n",
+						       ioinfo[irq]->senseid.cu_type,
+						       ioinfo[irq]->senseid.cu_model);
+				} else {
+					len += sprintf(info->data+len, "%04X/%02X\n",
+						       ioinfo[irq]->senseid.dev_type,
+						       ioinfo[irq]->senseid.dev_model);
+					len+= sprintf(info->data+len, "CU Type/Mod:  %04X/%02X\n",
+						      ioinfo[irq]->senseid.cu_type,
+						      ioinfo[irq]->senseid.cu_model);
 				}
 			}
 			info->len = len;
@@ -7115,6 +7017,7 @@
 	tempinfo_t *info;
 	int irq;
 	int devno;
+	char * devno_str;
 
 	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
 	if (info == NULL) {
@@ -7129,12 +7032,13 @@
 			vfree(info);
 			rc = -ENOMEM;
 		} else {
-			devno = cio_search_devno_by_inode(inode);
-			if (devno != -1) {
-				irq = get_irq_by_devno(devno);
-				if (irq != -1) {
-					len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
-				}
+			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
+			memset(devno_str, 0, 6*sizeof(char));
+			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
+			devno = simple_strtoul(devno_str, &devno_str, 16);
+			irq = get_irq_by_devno(devno);
+			if (irq != -1) {
+				len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
 			}
 			info->len = len;
 		}
@@ -7152,6 +7056,7 @@
 	int irq;
 	int devno;
 	int i;
+	char * devno_str;
 
 	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
 	if (info == NULL) {
@@ -7166,14 +7071,15 @@
 			vfree(info);
 			rc = -ENOMEM;
 		} else {
-			devno = cio_search_devno_by_inode(inode);
-			if (devno != -1) {
-				irq = get_irq_by_devno(devno);
-				if (irq != -1) {
-					for (i=0; i<8; i++) {
-						len += sprintf(info->data+len, "CHPID[%d]: ", i);
-						len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
-					}
+			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
+			memset(devno_str, 0, 6*sizeof(char));
+			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
+			devno = simple_strtoul(devno_str, &devno_str, 16);
+			irq = get_irq_by_devno(devno);
+			if (irq != -1) {
+				for (i=0; i<8; i++) {
+					len += sprintf(info->data+len, "CHPID[%d]: ", i);
+					len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
 				}
 			}
 			info->len = len;
@@ -7377,6 +7283,8 @@
  * un-ignore devices by piping to /proc/cio_ignore:
  * free all frees all blacklisted devices, free <range>,<range>,...
  * frees specified ranges of devnos
+ * add <range>,<range>,... will add a range of devices to blacklist -
+ * but only for devices not already known
  */
 
 static struct proc_dir_entry *cio_ignore_proc_entry;
@@ -7388,6 +7296,7 @@
 	int len = 0;
 	tempinfo_t *info;
 	dev_blacklist_range_t *tmp;
+	long flags;
 
 	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
 	if (info == NULL) {
@@ -7402,6 +7311,7 @@
 			vfree (info);
 			rc = -ENOMEM;
 		} else {
+			spin_lock_irqsave( &blacklist_lock, flags ); 
 			tmp = dev_blacklist_range_head;
 			while (tmp) {
 				len += sprintf(info->data+len, "%04x ", tmp->from);
@@ -7410,6 +7320,7 @@
 				len += sprintf(info->data+len, "\n");
 				tmp = tmp->next;
 			}
+			spin_unlock_irqrestore( &blacklist_lock, flags );
 			info->len = len;
 		}
 	}
@@ -7486,6 +7397,98 @@
 }
 
 __initcall(cio_ignore_proc_init);
+
+/*
+ * Entry /proc/irq_count
+ * display how many irqs have occured per cpu...
+ */
+
+static struct proc_dir_entry *cio_irq_proc_entry;
+
+static int cio_irq_proc_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	int i;
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += NR_CPUS * 16;
+		info->data = (char *) vmalloc(size);
+		if (size && info->data == NULL) {
+			printk( KERN_WARNING "No memory available for data\n");
+			vfree (info);
+			rc = -ENOMEM;
+		} else {
+			for (i=0; i< NR_CPUS; i++) {
+				if (s390_irq_count[i] != 0) 
+					len += sprintf(info->data+len, "%lx\n", s390_irq_count[i]);
+			}
+			info->len = len;
+		}
+	}
+	return rc;
+}
+
+static int cio_irq_proc_close(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (p_info) {
+		if (p_info->data) 
+			vfree(p_info->data);
+		vfree(p_info);
+	}
+
+	return rc;
+}
+
+static ssize_t cio_irq_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+	
+	if ( *offset>=p_info->len) {
+		return 0;
+	} else {
+		len = MIN(user_len, (p_info->len - *offset));
+		if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT; 
+		(* offset) += len;
+		return len;
+	}
+}
+
+static struct file_operations cio_irq_proc_file_ops = 
+	{
+		read:    cio_irq_proc_read,
+		open:    cio_irq_proc_open,
+		release: cio_irq_proc_close,
+	};
+
+static int cio_irq_proc_init(void)
+{
+
+	int i;
+
+	if (cio_count_irqs) {
+		for (i=0; i<NR_CPUS; i++) 
+			s390_irq_count[i]=0;
+		cio_irq_proc_entry = create_proc_entry("irq_count", S_IFREG|S_IRUGO, &proc_root);
+		cio_irq_proc_entry->proc_fops = &cio_irq_proc_file_ops;
+	}
+
+	return 1;
+}
+
+__initcall(cio_irq_proc_init);	
 
 /* end of procfs stuff */
 

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