diff -ruN linux-2.4.21/arch/s390x/kernel/ioctl32.c linux-2.3/arch/s390x/kernel/ioctl32.c
--- linux-2.4.21/arch/s390x/kernel/ioctl32.c	2004-09-08 15:38:11.000000000 +0200
+++ linux-2.3/arch/s390x/kernel/ioctl32.c	2004-08-14 07:57:53.000000000 +0200
@@ -625,14 +625,23 @@
   u32          u_mult_inv;
 } ica_rsa_modexpo_crt_32_t;
 
-#define ICA_IOCTL_MAGIC 'z'
-#define ICARSAMODEXPO   _IOC(_IOC_READ|_IOC_WRITE, ICA_IOCTL_MAGIC, 0x05, 0)
-#define ICARSACRT       _IOC(_IOC_READ|_IOC_WRITE, ICA_IOCTL_MAGIC, 0x06, 0) 
-#define ICARSAMODMULT   _IOC(_IOC_READ|_IOC_WRITE, ICA_IOCTL_MAGIC, 0x07, 0)
-#define ICAZ90STATUS    _IOC(_IOC_READ, ICA_IOCTL_MAGIC, 0x10, sizeof(ica_z90_status))
-#define ICAZ90QUIESCE   _IOC(_IOC_NONE, ICA_IOCTL_MAGIC, 0x11, 0)
-#define ICAZ90HARDRESET _IOC(_IOC_NONE, ICA_IOCTL_MAGIC, 0x12, 0)
-#define ICAZ90HARDERROR _IOC(_IOC_NONE, ICA_IOCTL_MAGIC, 0x13, 0)
+#define Z90_IOCTL_MAGIC 'z'
+#define ICARSAMODEXPO   _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x05, 0)
+#define ICARSACRT       _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x06, 0)
+#define ICAZ90STATUS    _IOR(Z90_IOCTL_MAGIC, 0x10, ica_z90_status)
+#define Z90QUIESCE      _IO(Z90_IOCTL_MAGIC, 0x11)
+#define Z90STAT_TOTALCOUNT      _IOR(Z90_IOCTL_MAGIC, 0x40, int)
+#define Z90STAT_PCICACOUNT      _IOR(Z90_IOCTL_MAGIC, 0x41, int)
+#define Z90STAT_PCICCCOUNT      _IOR(Z90_IOCTL_MAGIC, 0x42, int)
+#define Z90STAT_PCIXCCCOUNT     _IOR(Z90_IOCTL_MAGIC, 0x43, int)
+#define Z90STAT_REQUESTQ_COUNT  _IOR(Z90_IOCTL_MAGIC, 0x44, int)
+#define Z90STAT_PENDINGQ_COUNT  _IOR(Z90_IOCTL_MAGIC, 0x45, int)
+#define Z90STAT_TOTALOPEN_COUNT _IOR(Z90_IOCTL_MAGIC, 0x46, int)
+#define Z90STAT_DOMAIN_INDEX    _IOR(Z90_IOCTL_MAGIC, 0x47, int)
+#define Z90STAT_STATUS_MASK     _IOR(Z90_IOCTL_MAGIC, 0x48, char[64])
+#define Z90STAT_QDEPTH_MASK     _IOR(Z90_IOCTL_MAGIC, 0x49, char[64])
+#define Z90STAT_PERDEV_REQCNT   _IOR(Z90_IOCTL_MAGIC, 0x4a, int[64])
+
 
 static int do_rsa_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -1041,11 +1050,19 @@
 
 	IOCTL32_HANDLER(ICARSAMODEXPO, do_rsa_ioctl),
 	IOCTL32_HANDLER(ICARSACRT, do_rsa_crt_ioctl),
-	IOCTL32_HANDLER(ICARSAMODMULT, do_rsa_ioctl),
 	IOCTL32_DEFAULT(ICAZ90STATUS),
-	IOCTL32_DEFAULT(ICAZ90QUIESCE),
-	IOCTL32_DEFAULT(ICAZ90HARDRESET),
-	IOCTL32_DEFAULT(ICAZ90HARDERROR),
+	IOCTL32_DEFAULT(Z90QUIESCE),
+	IOCTL32_DEFAULT(Z90STAT_TOTALCOUNT),
+	IOCTL32_DEFAULT(Z90STAT_PCICACOUNT),
+	IOCTL32_DEFAULT(Z90STAT_PCICCCOUNT),
+	IOCTL32_DEFAULT(Z90STAT_PCIXCCCOUNT),
+	IOCTL32_DEFAULT(Z90STAT_REQUESTQ_COUNT),
+	IOCTL32_DEFAULT(Z90STAT_PENDINGQ_COUNT),
+	IOCTL32_DEFAULT(Z90STAT_TOTALOPEN_COUNT),
+	IOCTL32_DEFAULT(Z90STAT_DOMAIN_INDEX),
+	IOCTL32_DEFAULT(Z90STAT_STATUS_MASK),
+	IOCTL32_DEFAULT(Z90STAT_QDEPTH_MASK),
+	IOCTL32_DEFAULT(Z90STAT_PERDEV_REQCNT),
 
 /* Raw devices */
 	IOCTL32_DEFAULT(RAW_SETBIND),
diff -ruN linux-2.4.21/arch/s390x/kernel/linux32.c linux-2.3/arch/s390x/kernel/linux32.c
--- linux-2.4.21/arch/s390x/kernel/linux32.c	2004-09-08 15:38:10.000000000 +0200
+++ linux-2.3/arch/s390x/kernel/linux32.c	2004-08-16 14:19:32.000000000 +0200
@@ -4427,7 +4427,7 @@
     ret = sys_newstat(tmp, &s);
     set_fs (old_fs);
     putname(tmp);
-    if (putstat64 (statbuf, &s)) 
+    if (!ret && putstat64 (statbuf, &s)) 
 	    return -EFAULT;
     return ret;
 }
@@ -4451,7 +4451,7 @@
     ret = sys_newlstat(tmp, &s);
     set_fs (old_fs);
     putname(tmp);
-    if (putstat64 (statbuf, &s)) 
+    if (!ret && putstat64 (statbuf, &s)) 
 	    return -EFAULT;
     return ret;
 }
@@ -4467,7 +4467,7 @@
     set_fs (KERNEL_DS);
     ret = sys_newfstat(fd, &s);
     set_fs (old_fs);
-    if (putstat64 (statbuf, &s))
+    if (!ret && putstat64 (statbuf, &s))
 	    return -EFAULT;
     return ret;
 }
@@ -4507,7 +4507,7 @@
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
 		/* Result is out of bounds.  */
-		do_munmap(current->mm, addr, len);
+		do_munmap(current->mm, error, len);
 		error = -ENOMEM;
 	}
 	up_write(&current->mm->mmap_sem);
diff -ruN linux-2.4.21/drivers/s390/block/dasd.c linux-2.3/drivers/s390/block/dasd.c
--- linux-2.4.21/drivers/s390/block/dasd.c	2004-09-08 15:38:11.000000000 +0200
+++ linux-2.3/drivers/s390/block/dasd.c	2004-07-27 15:24:59.000000000 +0200
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.298.2.10 $
+ * $Revision: 1.298.2.11 $
  *
  * History of changes (starts July 2000)
  * 11/09/00 complete redesign after code review
@@ -5205,6 +5205,7 @@
                          "/proc/dasd/statistics: only 'set' and "
                          "'reset' are supported verbs");
 
+		vfree (buffer);
         	return -EINVAL;
 	}
 
@@ -5260,6 +5261,7 @@
         
 
 #endif /* DASD_PROFILE */
+        vfree (buffer);
 	return user_len;
 }
 
diff -ruN linux-2.4.21/drivers/s390/char/sclp.c linux-2.3/drivers/s390/char/sclp.c
--- linux-2.4.21/drivers/s390/char/sclp.c	2004-09-08 15:38:11.000000000 +0200
+++ linux-2.3/drivers/s390/char/sclp.c	2004-08-23 17:47:15.000000000 +0200
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/processor.h>
@@ -53,13 +54,18 @@
 /* Timer for init mask retries. */
 static struct timer_list retry_timer;
 
+/* Timer for busy retries. */
+static struct timer_list sclp_busy_timer;
+
 static volatile unsigned long sclp_status = 0;
 /* some status flags */
 #define SCLP_INIT		0
 #define SCLP_RUNNING		1
 #define SCLP_READING		2
+#define SCLP_SHUTDOWN		3
 
 #define SCLP_INIT_POLL_INTERVAL	1
+#define SCLP_BUSY_POLL_INTERVAL	1
 
 #define SCLP_COMMAND_INITIATED	0
 #define SCLP_BUSY		2
@@ -94,45 +100,61 @@
 	 */
 	if (cc == SCLP_NOT_OPERATIONAL)
 		return -EIO;
-	/*
-	 * We set the SCLP_RUNNING bit for cc 2 as well because if
-	 * service_call returns cc 2 some old request is running
-	 * that has to complete first
-	 */
-	set_bit(SCLP_RUNNING, &sclp_status);
 	if (cc == SCLP_BUSY)
 		return -EBUSY;
 	return 0;
 }
 
-static int
+static void
 sclp_start_request(void)
 {
 	struct sclp_req *req;
 	int rc;
 	unsigned long flags;
 
-	/* quick exit if sclp is already in use */
-	if (test_bit(SCLP_RUNNING, &sclp_status))
-		return -EBUSY;
 	spin_lock_irqsave(&sclp_lock, flags);
-	/* Get first request on queue if available */
-	req = NULL;
-	if (!list_empty(&sclp_req_queue))
+	/* quick exit if sclp is already in use */
+	if (test_bit(SCLP_RUNNING, &sclp_status)) {
+		spin_unlock_irqrestore(&sclp_lock, flags);
+		return;
+	}
+	/* Try to start requests from the request queue. */
+	while (!list_empty(&sclp_req_queue)) {
 		req = list_entry(sclp_req_queue.next, struct sclp_req, list);
-	if (req) {
 		rc = __service_call(req->command, req->sccb);
-		if (rc) {
-			req->status = SCLP_REQ_FAILED;
-			list_del(&req->list);
-		} else
+		if (rc == 0) {
+			/* Sucessfully started request. */
 			req->status = SCLP_REQ_RUNNING;
-	} else
-		rc = -EINVAL;
+			/* Request active. Set running indication. */
+			set_bit(SCLP_RUNNING, &sclp_status);
+			break;
+		}
+		if (rc == -EBUSY) {
+			/**
+			 * SCLP is busy but no request is running.
+			 * Try again later.
+			 */
+			if (!timer_pending(&sclp_busy_timer) ||
+			    !mod_timer(&sclp_busy_timer,
+				       jiffies + SCLP_BUSY_POLL_INTERVAL*HZ)) {
+				sclp_busy_timer.function =
+					(void *) sclp_start_request;
+				sclp_busy_timer.expires =
+					jiffies + SCLP_BUSY_POLL_INTERVAL*HZ;
+				add_timer(&sclp_busy_timer);
+			}
+			break;
+		}
+		/* Request failed. */
+		req->status = SCLP_REQ_FAILED;
+		list_del(&req->list);
+		if (req->callback) {
+			spin_unlock_irqrestore(&sclp_lock, flags);
+			req->callback(req, req->callback_data);
+			spin_lock_irqsave(&sclp_lock, flags);
+		}
+	}
 	spin_unlock_irqrestore(&sclp_lock, flags);
-	if (rc == -EIO && req->callback != NULL)
-		req->callback(req, req->callback_data);
-	return rc;
 }
 
 static int
@@ -587,10 +609,12 @@
 	sccb->mask_length = sizeof(sccb_mask_t);
 	/* copy in the sccb mask of the registered event types */
 	spin_lock_irqsave(&sclp_lock, flags);
-	list_for_each(l, &sclp_reg_list) {
-		t = list_entry(l, struct sclp_register, list);
-		sccb->receive_mask |= t->receive_mask;
-		sccb->send_mask |= t->send_mask;
+	if (!test_bit(SCLP_SHUTDOWN, &sclp_status)) {
+		list_for_each(l, &sclp_reg_list) {
+			t = list_entry(l, struct sclp_register, list);
+			sccb->receive_mask |= t->receive_mask;
+			sccb->send_mask |= t->send_mask;
+		}
 	}
 	sccb->sclp_receive_mask = 0;
 	sccb->sclp_send_mask = 0;
@@ -615,6 +639,8 @@
 		 */
 		do {
 			rc = __service_call(req->command, req->sccb);
+			if (rc == 0)
+				set_bit(SCLP_RUNNING, &sclp_status);
 			spin_unlock_irqrestore(&sclp_lock, flags);
 			if (rc == -EIO)
 				return -ENOSYS;
@@ -626,9 +652,10 @@
 		/* WRITEMASK failed - we cannot rely on receiving a state
 		   change event, so initially, polling is the only alternative
 		   for us to ever become operational. */
-		if (!timer_pending(&retry_timer) ||
-		    !mod_timer(&retry_timer,
-			       jiffies + SCLP_INIT_POLL_INTERVAL*HZ)) {
+		if (!test_bit(SCLP_SHUTDOWN, &sclp_status) &&
+		    (!timer_pending(&retry_timer) ||
+		     !mod_timer(&retry_timer,
+			       jiffies + SCLP_INIT_POLL_INTERVAL*HZ))) {
 			retry_timer.function = sclp_init_mask_retry;
 			retry_timer.data = 0;
 			retry_timer.expires = jiffies +
@@ -650,6 +677,26 @@
 	sclp_init_mask();
 }
 
+/* Reboot event handler - reset send and receive mask to prevent pending SCLP
+ * events from interfering with rebooted system. */
+static int
+sclp_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	unsigned long flags;
+
+	/* Note: need spinlock to maintain atomicity when accessing global
+         * variables. */
+	spin_lock_irqsave(&sclp_lock, flags);
+	set_bit(SCLP_SHUTDOWN, &sclp_status);
+	spin_unlock_irqrestore(&sclp_lock, flags);
+	sclp_init_mask();
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block sclp_reboot_notifier = {
+	.notifier_call = sclp_reboot_event
+};
+
 /*
  * sclp setup function. Called early (no kmalloc!) from sclp_console_init().
  */
@@ -670,6 +717,10 @@
 	list_add(&sclp_state_change_event.list, &sclp_reg_list);
 	list_add(&sclp_quiesce_event.list, &sclp_reg_list);
 
+	rc = register_reboot_notifier(&sclp_reboot_notifier);
+	if (rc)
+		return rc;
+
 	/*
 	 * request the 0x2401 external interrupt
 	 * The sclp driver is initialized early (before kmalloc works). We
@@ -687,6 +738,7 @@
 	ctl_set_bit(0, 9);
 
 	init_timer(&retry_timer);
+	init_timer(&sclp_busy_timer);
 	/* do the initial write event mask */
 	rc = sclp_init_mask();
 	if (rc == 0) {
diff -ruN linux-2.4.21/drivers/s390/misc/z90hardware.c linux-2.3/drivers/s390/misc/z90hardware.c
--- linux-2.4.21/drivers/s390/misc/z90hardware.c	2004-09-08 15:38:12.000000000 +0200
+++ linux-2.3/drivers/s390/misc/z90hardware.c	2004-07-15 17:35:28.000000000 +0200
@@ -35,7 +35,7 @@
 #define UINT unsigned int
 #define USHORT unsigned short
 #define UCHAR unsigned char
-#define VERSION_Z90HARDWARE_C "$Revision: 1.7.6.8 $"
+#define VERSION_Z90HARDWARE_C "$Revision: 1.7.6.9 $"
 static const char version[] =
        "z90crypt.o: z90hardware.o ("
        "z90hardware.c " VERSION_Z90HARDWARE_C "/"
@@ -800,7 +800,7 @@
 {
   int ccode;
 #ifdef __s390x__
-  asm volatile (" lgr   0,%4 \n"         
+  asm volatile (" llgfr   0,%4 \n"         
 		"\t slgr 1,1 \n"         
 		"\t lgr  2,1 \n"         
 #else
@@ -851,14 +851,14 @@
 		".previous"
 		:"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
 		:"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
-		:"cc","0","1","2");
+		:"cc","0","1","2","memory");
   return ccode;
 }; 
 inline int resetq (int q_nr, AP_STATUS_WORD *stat_p)
 {
   int ccode;
 #ifdef __s390x__
-  asm volatile ("\t lgr 0,%2 \n"         
+  asm volatile ("\t llgfr 0,%2 \n"         
 		"\t lghi 1,1  \n"        
 #else
   asm volatile ("\t lr 0,%2 \n"          
@@ -906,7 +906,7 @@
 		".previous"
 		:"=d" (ccode),"=d" (*stat_p)
 		:"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
-		:"cc","0","1","2");
+		:"cc","0","1","2","memory");
   return ccode;
 }; 
 inline int sen(int msg_len,
@@ -971,7 +971,7 @@
 		".previous"
 		:"=d" (ccode),"=d" (*stat)
 		:"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
-		:"cc","0","1","2","3","6","7");
+		:"cc","0","1","2","3","6","7","memory");
   return ccode;
 }; 
 inline int rec(int q_nr,
@@ -983,10 +983,10 @@
   int ccode;
   asm volatile
 #ifdef __s390x__
-    (" lgr 0,%2   \n"                    
+    (" llgfr 0,%2   \n"                    
      "\t lgr  3,%4 \n"                   
      "\t lgr  6,%3 \n"                   
-     "\t lgr  7,%5 \n"                   
+     "\t llgfr  7,%5 \n"                   
      "\t lghi 1,128 \n"                  
 #else
     (" lr 0,%2    \n"                    
diff -ruN linux-2.4.21/drivers/s390/misc/z90main.c linux-2.3/drivers/s390/misc/z90main.c
--- linux-2.4.21/drivers/s390/misc/z90main.c	2004-09-08 15:38:12.000000000 +0200
+++ linux-2.3/drivers/s390/misc/z90main.c	2004-07-15 17:35:28.000000000 +0200
@@ -55,7 +55,7 @@
 #include <linux/errno.h>   /* error codes */
 #include <linux/proc_fs.h>
 
-#define VERSION_Z90MAIN_C "$Revision: 1.9.4.10 $"
+#define VERSION_Z90MAIN_C "$Revision: 1.9.4.11 $"
 static const char version[] =
        "z90crypt.o: z90main.o ("
        "z90main.c "   VERSION_Z90MAIN_C   "/"
@@ -128,9 +128,15 @@
 
 //
 // Reader should run every READERTIME milliseconds
+// With the 100Hz patch for s390, z90crypt can lock the system solid while
+// under heavy load. We'll try to avoid that.
 //
 #ifndef READERTIME
+#if HZ > 1000
 #define READERTIME 2
+#else
+#define READERTIME 10
+#endif
 #endif
 
 // turn long device array index into device pointer
@@ -557,8 +563,8 @@
 /*---------------------------------------------------------------------------*/
 /* Documentation values.                                                     */
 /*---------------------------------------------------------------------------*/
-MODULE_AUTHOR("zLinux Crypto Team: Robert H. Burroughs and Eric D. Rossman");
-MODULE_DESCRIPTION("zLinux Cryptographic Coprocessor device driver,"
+MODULE_AUTHOR("zSeries Linux Crypto Team: Robert H. Burroughs and Eric D. Rossman");
+MODULE_DESCRIPTION("zSeries Linux Cryptographic Coprocessor device driver,"
 		   " Copyright 2001, 2003 IBM Corporation");
 MODULE_LICENSE("GPL");
 MODULE_PARM(domain, "i");
@@ -668,6 +674,11 @@
 
 	PDEBUG("init_module -> PID %d\n", PID());
 
+	if ((domain < -1) || (domain > 15)) {
+		PRINTKW("Invalid param: domain = %d.  Not loading.\n", domain);
+		return -EINVAL;
+	}
+
 	//
 	// Register the major (or get a dynamic one).
 	//
@@ -2103,7 +2114,6 @@
 void z90crypt_reader_task (unsigned long ptr)
 {
   int       workavail,
-            remaining,          /* number of unfinished requests            */
             index,
             rc, rv,
             buff_len;           /* Response length                          */
@@ -2118,7 +2128,6 @@
   struct list_head * hptr;      // pointer to list head
 
   workavail = 2;
-  remaining = 0;
   buff_len = 0;
   respaddr = NULL;
   remove_from_queue = FALSE;
@@ -2214,7 +2223,7 @@
           if (!(list_empty(&request_list))) {
             lptr = request_list.next;
             // Remove from queue
-            list_del(lptr);
+            list_del_init(lptr);
             requestq_count--;
             rq_p = list_entry(lptr, struct work_element, liste);
             rq_p->audit[1] |= FP_REMREQUEST;
@@ -2294,7 +2303,7 @@
         list_for_each_safe(lptr,tptr,hptr) {
           pq_p = list_entry(lptr, struct work_element, liste);
           if (!(memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id)))){
-            list_del(lptr);
+            list_del_init(lptr);
             --pendingq_count;
             pq_p->audit[1] |= FP_NOTPENDING;
             break;
@@ -2355,11 +2364,8 @@
        * Update the count of remaining work on this queue.
        */
       if (rc == REC_FATAL_ERROR)
-        remaining = 0;
-      else
-        if (rc != REC_NO_RESPONSE)
-          remaining += SHRT2DEVPTR(index)->z90c_dev_caller_count;
-
+        PRINTKW("REC_FATAL_ERROR from device %d!\n",
+                SHRT2LONG(index));
     } // end for each device
 
     // Unserialize
@@ -2370,13 +2376,11 @@
   //
   // Reschedule self, if there is still work on hardware.
   //
-  if (remaining) {
+  if (pendingq_count) {
     //
     // Schedule the reader_timer, if the previous step was successful.
     //
-    spin_lock_irq(&queuespinlock);
     rv = z90crypt_schedule_reader_timer();  // ignore rv; it's always 0
-    spin_unlock_irq(&queuespinlock);
   } // end if there's remaining work to do
 
 } // end z90crypt_reader_task
@@ -2439,7 +2443,7 @@
 			// get this off any caller queue it may be on
 			unbuild_caller(LONG2DEVPTR(pq_p->devindex),
 					   (Z90C_CALLER *)pq_p->requestptr);
-			list_del(lptr);
+			list_del_init(lptr);
 			pendingq_count--;
 			pq_p->audit[1] |= FP_NOTPENDING;
 			pq_p->audit[1] |= FP_AWAKENING;
@@ -2453,7 +2457,7 @@
 			pq_p = list_entry(lptr, struct work_element, liste);
 			pq_p->returncode = -ENODEV;
 			pq_p->status[0] |= STAT_FAILED;
-			list_del(lptr);
+			list_del_init(lptr);
 			requestq_count--;
 			pq_p->audit[1] |= FP_REMREQUEST;
 			pq_p->audit[1] |= FP_AWAKENING;
@@ -2483,12 +2487,21 @@
 		list_for_each_safe(lptr, tptr, hptr) {
 			pq_p = list_entry(lptr, struct work_element, liste);
 			if (pq_p->requestsent < timelimit) { // too old!
+				PRINTKW("Purging(PQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[0],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[1],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[2],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[3],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[4],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[5],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[6],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[7]);
 				pq_p->returncode = -ETIMEOUT;
 				pq_p->status[0] |= STAT_FAILED;
 				// get this off any caller queue it may be on
 				unbuild_caller(LONG2DEVPTR(pq_p->devindex),
 					(Z90C_CALLER *) pq_p->requestptr);
-				list_del(lptr);
+				list_del_init(lptr);
 				pendingq_count--;
 				pq_p->audit[1] |= FP_TIMEDOUT;
 				pq_p->audit[1] |= FP_NOTPENDING;
@@ -2511,9 +2524,18 @@
 				pq_p = list_entry(lptr,
 						struct work_element, liste);
 				if (pq_p->requestsent < timelimit) { // too old!
+				PRINTKW("Purging(RQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[0],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[1],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[2],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[3],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[4],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[5],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[6],
+		    ((struct z90c_caller *)pq_p->requestptr)->z90c_caller_id[7]);
 					pq_p->returncode = -ETIMEOUT;
 					pq_p->status[0] |= STAT_FAILED;
-					list_del(lptr);
+					list_del_init(lptr);
 					requestq_count--;
 					pq_p->audit[1] |= FP_TIMEDOUT;
 					pq_p->audit[1] |= FP_REMREQUEST;
@@ -2784,34 +2806,16 @@
 
   // If no devices have been found yet, first probe for domain
   if (z90crypt.z90c_hdware_info->z90c_hdware_mask.z90c_st_count == 0 &&
-      z90crypt.z90c_domain_established == FALSE)
+      z90crypt.z90c_domain_established == FALSE) {
     rv = probe_crypto_domain(cdx_p);
-
-  if (z90crypt.z90c_terminating == 1)
-    return TSQ_FATAL_ERROR;
-
-  if (rv == 0) {
-    if (*cdx_p) {
-      z90crypt.z90c_cdx = *cdx_p;
-      z90crypt.z90c_domain_established = TRUE;
-    }
-  }
-  else {
-    switch (rv)
-    {
-      case Z90C_AMBIGUOUS_DOMAIN:
-        PRINTK("More than one domain defined to this LPAR\n");
-        break;
-
-      case Z90C_INCORRECT_DOMAIN:
-        PRINTK("Specified domain doesn't match assigned domain\n");
-        break;
-
-      default:
-        PRINTK("Probe Domain returned %d\n",rv);
-        break;
-    }
-    return (rv);
+    if (z90crypt.z90c_terminating == 1)
+      return TSQ_FATAL_ERROR;
+    if (rv == Z90C_NO_DEVICES)
+      return 0; // try later
+    if (rv)
+      return rv;
+    z90crypt.z90c_cdx = *cdx_p;
+    z90crypt.z90c_domain_established = TRUE;
   }
 
   if ((rv = find_crypto_devices(&local_mask)) != OK) {
@@ -2972,6 +2976,7 @@
 {
   int rv = 0;
   int correct_cdx_found = 0;
+  char cdx_array_text[53], temp[5];
   int i,j,k;                  // loop counters
   HDSTAT hd_stat;             // device status
   int cdx_array[16];          // array of found cdx's
@@ -2980,9 +2985,9 @@
 
   k = 0;
   do {
+  for (j = 0; j <= 15; cdx_array[j++] = -1);
   for (i=0;i<z90crypt.z90c_max_count;i++) {
     hd_stat = HD_NOT_THERE;
-    for (j = 0; j <= 15; cdx_array[j++] = -1);
     k = 0;
     for (j = 0; j <= 15; j++) {
       hd_stat = query_on_line(i, j, MAX_RESET, &q_depth, &dev_type);
@@ -3018,26 +3023,32 @@
 
   switch(k) {
     case 0:
-      *cdx_p = 0;
-      rv = 0;
+      PRINTKW("Unable to find crypto domain: No devices found\n");
+      rv = Z90C_NO_DEVICES;
       break;
 
     case 1:
-      if (*cdx_p == -1 || z90crypt.z90c_domain_established == FALSE) {
+      if (*cdx_p == -1) {
         *cdx_p = cdx_array[0];
         rv = 0;
+        break;
       }
-      else {
-        if (*cdx_p != cdx_array[0]) {
-          PRINTK("probe_crypto_domain: Specified cdx: %d.  Assigned cdx: %d\n",*cdx_p,cdx_array[0]);
-          rv = Z90C_INCORRECT_DOMAIN;
-        }
-        else
-          rv = 0;
-      }
+      PRINTKW("incorrect domain: specified = %d, found = %d\n",
+             *cdx_p, cdx_array[0]);
+      rv = Z90C_INCORRECT_DOMAIN;
       break;
 
     default:
+      k--;
+      sprintf(cdx_array_text, "%d", cdx_array[k]);
+      while (k) {
+              k--;
+              sprintf(temp, ", %d", cdx_array[k]);
+              strcat(cdx_array_text, temp);
+      }
+
+      PRINTKW("ambiguous domain detected: specified = %d, found array = %s\n",
+              *cdx_p, cdx_array_text);
       rv = Z90C_AMBIGUOUS_DOMAIN;
       break;
   } // end switch
@@ -3975,6 +3986,10 @@
     }
 
     if (caller_p == NULL) {
+      PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
+              "%02X%02X%02X in device list\n",
+              psmid[0], psmid[1], psmid[2], psmid[3],
+              psmid[4], psmid[5], psmid[6], psmid[7]);
       rv = REC_USER_GONE;
       break;
     }
@@ -4358,7 +4373,7 @@
                                    // much space
   unsigned char *dyn_testmsg;
 
-  dyn_testmsg = kmalloc(testmsg_len, GFP_KERNEL);
+  dyn_testmsg = kmalloc(testmsg_len, GFP_ATOMIC);
   if (!dyn_testmsg) {
     PRINTK("kmalloc for dyn_testmsg failed in probe_device_type\n");
     return OK;  // Strange, but it will work. Since we didn't update the device
diff -ruN linux-2.4.21/drivers/s390/scsi/zfcp_fsf.h linux-2.3/drivers/s390/scsi/zfcp_fsf.h
--- linux-2.4.21/drivers/s390/scsi/zfcp_fsf.h	2004-09-08 15:38:12.000000000 +0200
+++ linux-2.3/drivers/s390/scsi/zfcp_fsf.h	2004-08-13 16:01:13.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * $Id: zfcp_fsf.h,v 1.7.2.3 2004/05/19 13:08:06 mpeschke Exp $
+ * $Id: zfcp_fsf.h,v 1.7.2.4 2004/08/13 14:01:13 aherrman Exp $
  *
  * header file for FCP adapter driver for IBM eServer zSeries
  *
@@ -207,6 +207,11 @@
 #define FSF_HBA_PORTSTATE_LINKDOWN		0x00000006
 #define FSF_HBA_PORTSTATE_ERROR			0x00000007
 
+/* IO states of adapter */
+#define FSF_IOSTAT_NPORT_RJT			0x00000004
+#define FSF_IOSTAT_FABRIC_RJT			0x00000005
+#define FSF_IOSTAT_LS_RJT			0x00000009
+
 
 struct fsf_queue_designator;
 struct fsf_status_read_buffer;
diff -ruN linux-2.4.21/drivers/s390/scsi/zfcp.h linux-2.3/drivers/s390/scsi/zfcp.h
--- linux-2.4.21/drivers/s390/scsi/zfcp.h	2004-09-08 15:38:12.000000000 +0200
+++ linux-2.3/drivers/s390/scsi/zfcp.h	2004-08-13 16:01:13.000000000 +0200
@@ -144,6 +144,7 @@
 #define ZFCP_CT_GA_NXT			0x0100
 #define ZFCP_CT_MAX_SIZE		0x1020
 #define ZFCP_CT_ACCEPT			0x8002
+#define ZFCP_CT_REJECT			0x8001
 
 /*
  * FC-FS stuff
@@ -171,13 +172,11 @@
 #define ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED	0x0B
 #define ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR		0xFF
 
-struct zfcp_ls_rjt {
-	u8		code;
-	u8		field[3];
-	u8		reserved;
-	u8		reason_code;
-	u8		reason_expl;
-	u8		vendor_unique;
+struct zfcp_ls_rjt_par {
+	u8 action;
+ 	u8 reason_code;
+ 	u8 reason_expl;
+ 	u8 vendor_unique;
 } __attribute__ ((packed));
 
 struct zfcp_ls_rtv {
@@ -298,6 +297,12 @@
 			specific_id;
 } __attribute__((packed));
 
+struct zfcp_rc_entry {
+	u8 code;
+	const char *description;
+};
+
+
 /*
  * FC-GS-4 stuff
  */
@@ -394,7 +399,7 @@
 	struct ct_iu_gid_pn ct_iu_resp;
 };
 
-typedef int (*zfcp_send_els_handler_t)(unsigned long);
+typedef void (*zfcp_send_els_handler_t)(unsigned long);
 
 /* used to pass parameters to zfcp_send_els() */
 struct zfcp_send_els {
@@ -1288,5 +1293,7 @@
 int zfcp_ns_ga_nxt_request(zfcp_port_t *, struct ct_iu_ga_nxt *);
 int zfcp_fsf_send_ct(struct zfcp_send_ct *, zfcp_mem_pool_t *,
 		     zfcp_erp_action_t *);
+extern int  zfcp_check_ct_response(struct ct_hdr *);
+extern int  zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *);
 
 #endif /* _ZFCP_H_ */
diff -ruN linux-2.4.21/drivers/s390/scsi/zfcp_main.c linux-2.3/drivers/s390/scsi/zfcp_main.c
--- linux-2.4.21/drivers/s390/scsi/zfcp_main.c	2004-09-08 15:38:12.000000000 +0200
+++ linux-2.3/drivers/s390/scsi/zfcp_main.c	2004-08-20 14:06:10.000000000 +0200
@@ -14,7 +14,7 @@
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_REVISION		"$Revision: 1.31.2.11 $"
+#define ZFCP_REVISION		"$Revision: 1.31.2.16 $"
 
 #define ZFCP_QTCB_VERSION	FSF_QTCB_CURRENT_VERSION
 
@@ -958,7 +958,7 @@
 
 /* prototypes for extended link services functions */
 static int zfcp_els(zfcp_port_t*, u8);
-static int zfcp_els_handler(unsigned long);
+static void zfcp_els_handler(unsigned long);
 static int zfcp_test_link(zfcp_port_t*);
 
 /* prototypes for error recovery functions */
@@ -9061,15 +9061,11 @@
                 break;
         case FSF_SQ_ULP_PROGRAMMING_ERROR :
                 ZFCP_LOG_FLAGS(0, "FSF_SQ_ULP_PROGRAMMING_ERROR\n");
-                ZFCP_LOG_NORMAL("bug: An illegal amount of data was attempted "
-                                "to be sent to the adapter with devno 0x%04x "
-                                "Stopping all operations on this adapter. ",
+		ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer "
+				"(adapter devno=0x%04x)\n",
                                 fsf_req->adapter->devno);
-                debug_text_exception(fsf_req->adapter->erp_dbf,0,"fsf_sq_ulp_err");
-                zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
-		zfcp_cmd_dbf_event_fsf(
-			"squlperr", fsf_req,
-			&fsf_req->qtcb->header.fsf_status_qual, sizeof(fsf_status_qual_t));
+                debug_text_exception(fsf_req->adapter->erp_dbf, 0,
+                                     "fsf_sq_ulp_err");
                 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                 break;
         case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
@@ -10315,15 +10311,7 @@
 
 	ZFCP_LOG_TRACE("enter\n");
 
-        if (ct_iu_resp->header.revision != ZFCP_CT_REVISION)
-		goto failed;
-        if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE)
-		goto failed;
-        if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER)
-		goto failed;
-        if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
-		goto failed;
-        if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
+	if (zfcp_check_ct_response(&ct_iu_resp->header)) {
 		/* FIXME: do we need some specific erp entry points */
 		atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
 		goto failed;
@@ -10351,7 +10339,7 @@
 		port->d_id);
 	goto out;
 
-failed:
+ failed:
 	ZFCP_LOG_NORMAL(
 		"warning: WWPN 0x%016Lx not found by nameserver lookup "
 		"using the adapter with devno 0x%04x\n", 
@@ -10367,7 +10355,7 @@
 		(char*)ct_iu_resp,
 		sizeof(struct ct_iu_gid_pn));
 
-out:
+ out:
         zfcp_gid_pn_buffers_free(erp_action->data.gid_pn);
         erp_action->data.gid_pn = 0;
 	ZFCP_LOG_TRACE("exit\n");
@@ -10505,20 +10493,12 @@
 
 	ZFCP_LOG_TRACE("enter\n");
 
-        if (ct_iu_resp->header.revision != ZFCP_CT_REVISION)
-		goto failed;
-        if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE)
-		goto failed;
-        if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER)
-		goto failed;
-        if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
-		goto failed;
-        if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT)
+	if (zfcp_check_ct_response(&ct_iu_resp->header))
 		goto failed;
 
 	goto out;
 
-failed:
+ failed:
         ct->status = -EIO;
 	ZFCP_LOG_DEBUG("CT IU headers do not match:\n");
 	ZFCP_HEX_DUMP(
@@ -10540,6 +10520,176 @@
 #undef ZFCP_LOG_AREA_PREFIX
 }
 
+/* reject CT_IU reason codes acc. to FC-GS-4 */
+static const struct zfcp_rc_entry zfcp_ct_rc[] = {
+	{0x01, "invalid command code"},
+	{0x02, "invalid version level"},
+	{0x03, "logical error"},
+	{0x04, "invalid CT_IU size"},
+	{0x05, "logical busy"},
+	{0x07, "protocol error"},
+	{0x09, "unable to perform command request"},
+	{0x0b, "command not supported"},
+	{0x0d, "server not available"},
+	{0x0e, "session could not be established"},
+	{0xff, "vendor specific error"},
+	{0, NULL},
+};
+
+/* LS_RJT reason codes acc. to FC-FS */
+static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = {
+	{0x01, "invalid LS_Command code"},
+	{0x03, "logical error"},
+	{0x05, "logical busy"},
+	{0x07, "protocol error"},
+	{0x09, "unable to perform command request"},
+	{0x0b, "command not supported"},
+	{0x0e, "command already in progress"},
+	{0xff, "vendor specific error"},
+	{0, NULL},
+};
+
+/* reject reason codes according to FC-PH/FC-FS */
+static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
+	{0x01, "invalid D_ID"},
+	{0x02, "invalid S_ID"},
+	{0x03, "Nx_Port not available, temporary"},
+	{0x04, "Nx_Port not available, permament"},
+	{0x05, "class not supported"},
+	{0x06, "delimiter usage error"},
+	{0x07, "TYPE not supported"},
+	{0x08, "invalid Link_Control"},
+	{0x09, "invalid R_CTL field"},
+	{0x0a, "invalid F_CTL field"},
+	{0x0b, "invalid OX_ID"},
+	{0x0c, "invalid RX_ID"},
+	{0x0d, "invalid SEQ_ID"},
+	{0x0e, "invalid DF_CTL"},
+	{0x0f, "invalid SEQ_CNT"},
+	{0x10, "invalid parameter field"},
+	{0x11, "exchange error"},
+	{0x12, "protocol error"},
+	{0x13, "incorrect length"},
+	{0x14, "unsupported ACK"},
+	{0x15, "class of service not supported by entity at FFFFFE"},
+	{0x16, "login required"},
+	{0x17, "excessive sequences attempted"},
+	{0x18, "unable to establish exchange"},
+	{0x1a, "fabric path not available"},
+	{0x1b, "invalid VC_ID (class 4)"},
+	{0x1c, "invalid CS_CTL field"},
+	{0x1d, "insufficient resources for VC (class 4)"},
+	{0x1f, "invalid class of service"},
+	{0x20, "preemption request rejected"},
+	{0x21, "preemption not enabled"},
+	{0x22, "multicast error"},
+	{0x23, "multicast error terminate"},
+	{0x24, "process login required"},
+	{0xff, "vendor specific reject"},
+	{0, NULL},
+};
+
+#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_OTHER
+#define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_OTHER
+/**
+ * zfcp_rc_description - return description for given reaon code
+ * @code: reason code
+ * @rc_table: table of reason codes and descriptions
+ */
+static inline const char *
+zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
+{
+	const char *descr = "unknown reason code";
+
+	do {
+		if (code == rc_table->code) {
+			descr = rc_table->description;
+			break;
+		}
+		rc_table++;
+	} while (rc_table->code && rc_table->description);
+
+	return descr;
+}
+		     
+/**
+ * zfcp_check_ct_response - evaluate reason code for CT_IU
+ * @rjt: response payload to an CT_IU request
+ * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code
+ */
+int
+zfcp_check_ct_response(struct ct_hdr *rjt)
+{
+	if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT)
+		return 0;
+
+	if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) {
+		ZFCP_LOG_NORMAL("error: invalid Generic Service command/"
+				"response code (0x%04hx)\n",
+				rjt->cmd_rsp_code);
+		return 1;
+	}
+
+	ZFCP_LOG_INFO("Generic Service command rejected\n");
+	ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n",
+		      zfcp_rc_description(rjt->reason_code, zfcp_ct_rc),
+		      (u32) rjt->reason_code, (u32) rjt->reason_code_expl,
+		      (u32) rjt->vendor_unique);
+
+	return 1;
+}
+
+/**
+ * zfcp_print_els_rjt - print reject parameter and description for ELS reject
+ * @rjt_par: reject parameter acc. to FC-PH/FC-FS
+ * @rc_table: table of reason codes and descriptions
+ */
+static inline void
+zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
+		   const struct zfcp_rc_entry *rc_table)
+{
+	ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n",
+		      zfcp_rc_description(rjt_par->reason_code, rc_table),
+		      (u32) rjt_par->action, (u32) rjt_par->reason_code,
+		      (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique);
+}
+
+/**
+ * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject
+ * @sq: status qualifier word
+ * @rjt_par: reject parameter as described in FC-PH and FC-FS
+ * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else
+ */
+int
+zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par)
+{
+	int ret = -EIO;
+
+	if (sq == FSF_IOSTAT_NPORT_RJT) {
+		ZFCP_LOG_INFO("ELS rejected (P_RJT)\n");
+		zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc);
+		/* invalid d_id */
+		if (rjt_par->reason_code == 0x01)
+			ret = -EREMCHG;
+	} else if (sq == FSF_IOSTAT_FABRIC_RJT) {
+		ZFCP_LOG_INFO("ELS rejected (F_RJT)\n");
+		zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc);
+		/* invalid d_id */
+		if (rjt_par->reason_code == 0x01)
+			ret = -EREMCHG; 
+	} else if (sq == FSF_IOSTAT_LS_RJT) {
+		ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n");
+		zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc);
+		ret = -EREMOTEIO;
+	} else
+		ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq);
+
+	return ret;
+}
+#undef ZFCP_LOG_AREA
+#undef ZFCP_LOG_AREA_PREFIX
+
+
 /*
  * checks whether req buffer and resp bother fit into one SBALE each
  */
@@ -10883,7 +11033,9 @@
 	}
 
 skip_fsfstatus:
-	/* callback */
+	fsf_req->data.send_ct->status = retval;
+
+        /* callback */
 	if (fsf_req->data.send_ct->handler != 0) {
                 (fsf_req->data.send_ct->handler)
                         (fsf_req->data.send_ct->handler_data);
@@ -11045,6 +11197,10 @@
 			ZFCP_LOG_FLAGS(2, "FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n");
 			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+			retval =
+			  zfcp_handle_els_rjt(header->fsf_status_qual.word[1],
+					      (struct zfcp_ls_rjt_par *)
+					      &header->fsf_status_qual.word[2]);
 			break;
 
 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
@@ -15177,6 +15333,17 @@
         if(retval < 0)
                 goto failed_sbals;
 
+        /*
+         * We hold queue_lock here. Check if QDIOUP is set and let request fail
+         * if it is not set (see also *_open_qdio and *_close_qdio).
+         */
+
+        if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
+                write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags);
+                retval = -EIO;
+                goto failed_sbals;
+        }
+
 #ifndef ZFCP_PARANOIA_DEAD_CODE
 	/* set magics */
 	fsf_req->common_magic = ZFCP_MAGIC;
@@ -16329,16 +16496,12 @@
 }
 
 
-/*
- * function:    zfcp_els_handler
- *
- * purpose:     Handler for all kind of ELSs
- *
- * returns:     0       - Operation completed successfuly
- *              -ENXIO  - ELS has been rejected
- *              -EPERM  - Port forced reopen failed
+/**
+ * zfcp_els_handler - handler for ELS commands
+ * @data: pointer to struct zfcp_send_els
+ * If ELS failed (LS_RJT or timed out) forced reopen of the port is triggered.
  */
-static int zfcp_els_handler(unsigned long data)
+static void zfcp_els_handler(unsigned long data)
 {
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF
 #define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_FSF
@@ -16347,126 +16510,44 @@
 	zfcp_port_t *port = send_els->port;
 	zfcp_adapter_t *adapter = port->adapter;
 	u8 req_code = *(u8*)send_els->req->address;
-	u8 resp_code = *(u8*)send_els->resp->address;
-	struct zfcp_ls_rjt *rjt;
 	struct zfcp_ls_rtv_acc *rtv;
 	struct zfcp_ls_rls_acc *rls;
 	struct zfcp_ls_pdisc_acc *pdisc;
 	struct zfcp_ls_adisc_acc *adisc;
-	int retval = 0;
 
 	ZFCP_LOG_TRACE("enter (data=0x%lx)\n", data);
 
+	/* request rejected or timed out */
 	if (send_els->status != 0) {
-		ZFCP_LOG_NORMAL(
-			"ELS request timed out, force physical port reopen "
-			"(wwpn=0x%016Lx devno=0x%04x)\n",
-			(unsigned long long)port->wwpn,
-			adapter->devno);
+		ZFCP_LOG_NORMAL("ELS request failed, force physical port "
+			"reopen (wwpn=0x%016Lx devno=0x%04x)\n",
+			(unsigned long long)port->wwpn, adapter->devno);
 		debug_text_event(adapter->erp_dbf, 3, "forcreop");
-		retval = zfcp_erp_port_forced_reopen(port, 0);
-		if (retval != 0) {
+		if (zfcp_erp_port_forced_reopen(port, 0))
 			ZFCP_LOG_NORMAL(
 				"Cannot reopen a remote port "
 				"(wwpn=0x%016Lx devno=0x%04x)\n",
 				(unsigned long long)port->wwpn,
 				adapter->devno);
-			retval = -EPERM;
-		}
-		goto skip_fsfstatus;
+		goto out;
 	}
 
-	switch (resp_code) {
-
-	case ZFCP_LS_RJT:
-		rjt = (struct zfcp_ls_rjt*)send_els->resp->address;
-
-		switch (rjt->reason_code) {
-
-		case ZFCP_LS_RJT_INVALID_COMMAND_CODE:
-			ZFCP_LOG_NORMAL(
-				"Invalid command code "
-				"(wwpn=0x%016Lx command=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				req_code);
-			break;
-
-		case ZFCP_LS_RJT_LOGICAL_ERROR:
-			ZFCP_LOG_NORMAL(
-				"Logical error "
-				"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				rjt->reason_expl);
-			break;
-
-		case ZFCP_LS_RJT_LOGICAL_BUSY:
-			ZFCP_LOG_NORMAL(
-				"Logical busy "
-				"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				rjt->reason_expl);
-			break;
-
-		case ZFCP_LS_RJT_PROTOCOL_ERROR:
-			ZFCP_LOG_NORMAL(
-				"Protocol error "
-				"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				rjt->reason_expl);
-			break;
-
-		case ZFCP_LS_RJT_UNABLE_TO_PERFORM:
-			ZFCP_LOG_NORMAL(
-				"Unable to perform command requested "
-				"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				rjt->reason_expl);
-			break;
-
-		case ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED:
-			ZFCP_LOG_NORMAL(
-				"Command not supported "
-				"(wwpn=0x%016Lx command=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				req_code);
-			break;
-
-		case ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR:
-			ZFCP_LOG_NORMAL(
-				"Vendor unique error "
-				"(wwpn=0x%016Lx vendor_unique=0x%02x)\n",
-				(unsigned long long)port->wwpn,
-				rjt->vendor_unique);
-			break;
-
-		default:
-			ZFCP_LOG_NORMAL(
-				"ELS has been rejected "
-				"(devno=0x%04x wwpn=0x%016Lx reason_code=0x%02x)\n",
-				adapter->devno,
-				(unsigned long long)port->wwpn,
-				rjt->reason_code);
-		}
-		retval = -ENXIO;
-		break;
-
-	case ZFCP_LS_ACC:
-		switch (req_code) {
+        switch (req_code) {
 
-		case ZFCP_LS_RTV:
-			rtv = (struct zfcp_ls_rtv_acc*)send_els->resp->address;
-			ZFCP_LOG_NORMAL(
+        case ZFCP_LS_RTV:
+                rtv = (struct zfcp_ls_rtv_acc*)send_els->resp->address;
+                ZFCP_LOG_NORMAL(
 				"RTV response from did 0x%06x to sid 0x%06x "
 				"with payload(R_A_TOV=%ds E_D_TOV=%d%cs)\n",
 				port->d_id, port->adapter->s_id,
 				rtv->r_a_tov, rtv->e_d_tov,
 				rtv->qualifier & ZFCP_LS_RTV_E_D_TOV_FLAG ?
-					'n' : 'm');
-			break;
+                                'n' : 'm');
+                break;
 
-		case ZFCP_LS_RLS:
-			rls = (struct zfcp_ls_rls_acc*)send_els->resp->address;
-			ZFCP_LOG_NORMAL(
+        case ZFCP_LS_RLS:
+                rls = (struct zfcp_ls_rls_acc*)send_els->resp->address;
+                ZFCP_LOG_NORMAL(
 				"RLS response from did 0x%06x to sid 0x%06x "
 				"with payload(link_failure_count=%u "
 				"loss_of_sync_count=%u "
@@ -16481,11 +16562,11 @@
 				rls->prim_seq_prot_error,
 				rls->invalid_transmition_word,
 				rls->invalid_crc_count);
-			break;
+                break;
 
-		case ZFCP_LS_PDISC:
-			pdisc = (struct zfcp_ls_pdisc_acc*)send_els->resp->address;
-			ZFCP_LOG_NORMAL(
+        case ZFCP_LS_PDISC:
+                pdisc = (struct zfcp_ls_pdisc_acc*)send_els->resp->address;
+                ZFCP_LOG_NORMAL(
 				"PDISC response from did 0x%06x to sid 0x%06x "
 				"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
 				"vendor='%-16s')\n",
@@ -16493,11 +16574,11 @@
 				(unsigned long long)pdisc->wwpn,
 				(unsigned long long)pdisc->wwnn,
 				pdisc->vendor_version);
-			break;
+                break;
 
-		case ZFCP_LS_ADISC:
-			adisc = (struct zfcp_ls_adisc_acc*)send_els->resp->address;
-			ZFCP_LOG_NORMAL(
+        case ZFCP_LS_ADISC:
+                adisc = (struct zfcp_ls_adisc_acc*)send_els->resp->address;
+                ZFCP_LOG_NORMAL(
 				"ADISC response from did 0x%06x to sid 0x%06x "
 				"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
 				"hard_nport_id=0x%06x nport_id=0x%06x)\n",
@@ -16505,39 +16586,32 @@
 				(unsigned long long)adisc->wwpn,
 				(unsigned long long)adisc->wwnn,
 				adisc->hard_nport_id, adisc->nport_id);
-			/* FIXME: missing wwnn value in port struct */
+		if (port->wwpn != adisc->wwpn) {
+			ZFCP_LOG_NORMAL("d_id assignment changed, reopening "
+					"port (devno=0x%04x, wwpn=0x%016Lx, "
+					"adisc_resp_wwpn=0x%016Lx)\n",
+					adapter->devno,
+                                        (unsigned long long) port->wwpn,
+                                        (unsigned long long) adisc->wwpn);
+			if (zfcp_erp_port_reopen(port, 0))
+				ZFCP_LOG_NORMAL("failed reopen of port "
+						"(devno=0x%04x, "
+                                                "wwpn=0x%016Lx)\n",
+						adapter->devno,
+                                                (long long) port->wwpn);
+                } else
 			if (port->wwnn == 0)
 				port->wwnn = adisc->wwnn;
-			break;
-		}
-		break;
 
-	default:
-		ZFCP_LOG_NORMAL(
-			"Unknown payload code 0x%02x received on a request "
-			"0x%02x from sid 0x%06x to did 0x%06x, "
-			"port needs to be reopened\n",
-			req_code, resp_code, port->adapter->s_id, port->d_id);
-		retval = zfcp_erp_port_forced_reopen(port, 0);
-		if (retval != 0) {
-			ZFCP_LOG_NORMAL(
-				"Cannot reopen a remote port "
-				"(wwpn=0x%016Lx devno=0x%04x)\n",
-				(unsigned long long)port->wwpn,
-				port->adapter->devno);
-			retval = -EPERM;
-		}
-	}
+                break;
+        }
 
-skip_fsfstatus:
+ out:
 	ZFCP_FREE_PAGE((unsigned long)send_els->req->address);
 	ZFCP_KFREE(send_els->req, sizeof(struct scatterlist));
 	ZFCP_KFREE(send_els->resp, sizeof(struct scatterlist));
 
 	ZFCP_LOG_TRACE("exit (%i)\n", retval);
-
-	return retval;
-
 #undef ZFCP_LOG_AREA
 #undef ZFCP_LOG_AREA_PREFIX
 }
@@ -19147,8 +19221,6 @@
 	zfcp_adapter_t *adapter = erp_action->adapter;
 	int i;
 	volatile qdio_buffer_element_t *buffere;
-	int retval_cleanup = 0;
-	//unsigned long timeout = 300 * HZ;
 	
         ZFCP_LOG_TRACE("enter\n");
 
@@ -19241,19 +19313,13 @@
 	/* NOP */
 
 failed_qdio_activate:
-	/* DEBUG */
-	//__ZFCP_WAIT_EVENT_TIMEOUT(timeout, 0);
-	/* cleanup queues previously established */
-	retval_cleanup = qdio_cleanup(adapter->irq, QDIO_FLAG_CLEANUP_USING_CLEAR);
-	if (retval_cleanup) {
-		ZFCP_LOG_NORMAL(
-			"bug: Could not clean QDIO (data transfer mechanism) "
-                        "queues. (debug info %i).\n",
-			retval_cleanup);
-	}
-#ifdef ZFCP_DEBUG_REQUESTS
-          else  debug_text_event(adapter->req_dbf, 1, "q_clean");
-#endif /* ZFCP_DEBUG_REQUESTS */
+        debug_text_event(adapter->erp_dbf, 3, "qdio_down1a");
+        while (qdio_cleanup(adapter->irq,
+                            QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) {
+                set_current_state(TASK_UNINTERRUPTIBLE);
+                schedule_timeout(HZ);
+        }
+        debug_text_event(adapter->erp_dbf, 3, "qdio_down1b");
 
 	/*
 	 * First we had to stop QDIO operation.
@@ -19261,8 +19327,6 @@
 	 */
 
 failed_qdio_initialize:
-	atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
-
 failed_sanity:
 	retval = ZFCP_ERP_FAILED;
 
@@ -19290,9 +19354,6 @@
  
 	int retval = ZFCP_ERP_SUCCEEDED;
 	zfcp_adapter_t *adapter = erp_action->adapter;
-#if 0
-        unsigned long flags;
-#endif
 
 	ZFCP_LOG_TRACE("enter\n");
 
@@ -19306,51 +19367,22 @@
 		goto out;
 	}
 
-	/* cleanup queues previously established */
-
-	/*
-	 * MUST NOT LOCK - qdio_cleanup might call schedule
-	 * FIXME: need another way to make cleanup safe
-	 */
-        /* Note:
-         * We need the request_queue lock here, otherwise there exists the 
-         * following race:
-         * 
-         * queuecommand calls create_fcp_commmand_task...calls req_create, 
-         * gets sbal x to x+y - meanwhile adapter reopen is called, completes 
-         * - req_send calls do_QDIO for sbal x to x+y, i.e. wrong indices.
-         *
-         * with lock:
-         * queuecommand calls create_fcp_commmand_task...calls req_create, 
-         * gets sbal x to x+y - meanwhile adapter reopen is called, waits 
-         * - req_send calls do_QDIO for sbal x to x+y, i.e. wrong indices 
-         * but do_QDIO fails as adapter_reopen is still waiting for the lock
-         * OR
-         * queuecommand calls create_fcp_commmand_task...calls req_create 
-         * - meanwhile adapter reopen is called...completes,
-         * - gets sbal 0 to 0+y, - req_send calls do_QDIO for sbal 0 to 0+y, 
-         * i.e. correct indices...though an fcp command is called before 
-         * exchange config data...that should be fine, however
+        /*
+         * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that
+         * do_QDIO won't be called while qdio_shutdown is in progress.
          */
-#if 0
-        write_lock_irqsave(&adapter->request_queue.queue_lock, flags);
-#endif	//0
 
-	if (qdio_cleanup(adapter->irq, QDIO_FLAG_CLEANUP_USING_CLEAR) != 0) {
-		/*
-		 * FIXME(design):
-		 * What went wrong? What to do best? Proper retval?
-		 */
-		ZFCP_LOG_NORMAL(
-			"error: Clean-up of QDIO (data transfer mechanism) "
-                        "structures failed for adapter with devno 0x%04x.\n",
-			adapter->devno);
-	} else	{
-		ZFCP_LOG_DEBUG("queues cleaned up\n");
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 1, "q_clean");
-#endif /* ZFCP_DEBUG_REQUESTS */
-	}
+        write_lock_irq(&adapter->request_queue.queue_lock);
+        atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
+        write_unlock_irq(&adapter->request_queue.queue_lock);
+
+        debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
+        while (qdio_cleanup(adapter->irq,
+                            QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) {
+                set_current_state(TASK_UNINTERRUPTIBLE);
+                schedule_timeout(HZ);
+        }
+        debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
 
 	/*
 	 * First we had to stop QDIO operation.
@@ -19366,12 +19398,6 @@
         adapter->request_queue.free_index = 0;
         atomic_set(&adapter->request_queue.free_count, 0);
         adapter->request_queue.distance_from_int = 0;
-
-	atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
-
-#if 0
-        write_unlock_irqrestore(&adapter->request_queue.queue_lock, flags);
-#endif
 out:
 	ZFCP_LOG_TRACE("exit (%i)\n", retval);
  
@@ -21213,6 +21239,12 @@
 	wait_event(fsf_req->completion_wq,
 		   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
 
+	if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
+	    (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
+		retval = -ENXIO;
+		goto out;
+	}
+
 	sense_data.fsf_status = fsf_req->qtcb->header.fsf_status;
 	memcpy(&sense_data.fsf_status_qual,
 	       &fsf_req->qtcb->header.fsf_status_qual,
diff -ruN linux-2.4.21/drivers/s390/scsi/zfcp_zh.c linux-2.3/drivers/s390/scsi/zfcp_zh.c
--- linux-2.4.21/drivers/s390/scsi/zfcp_zh.c	2004-09-08 15:38:12.000000000 +0200
+++ linux-2.3/drivers/s390/scsi/zfcp_zh.c	2004-08-13 16:01:13.000000000 +0200
@@ -1,5 +1,5 @@
 /* 
- * $Id: zfcp_zh.c,v 1.3.2.2 2004/06/08 10:10:29 mpeschke Exp $
+ * $Id: zfcp_zh.c,v 1.3.2.3 2004/08/13 14:01:13 aherrman Exp $
  *
  * Module providing an interface for HBA API (FC-HBA) implementation
  * to the zfcp driver.
@@ -724,6 +724,10 @@
 	ret = zfcp_fsf_send_ct(&ct, 0, 0);
 	if (0 == ret) {
 		wait_for_completion(&wait);
+		if (ct.status)
+			ret = -EIO;
+		else
+			zfcp_check_ct_response((void *)resp->address);
 	}
 
 	return ret;
diff -ruN linux-2.4.21/fs/partitions/ibm.c linux-2.3/fs/partitions/ibm.c
--- linux-2.4.21/fs/partitions/ibm.c	2004-09-08 15:38:10.000000000 +0200
+++ linux-2.3/fs/partitions/ibm.c	2004-08-11 16:38:49.000000000 +0200
@@ -162,7 +162,8 @@
 		add_gd_partition(hd, first_part_minor,
 				 offset*(blocksize >> 9),
 				 size-offset*(blocksize >> 9));
-	} else if (strncmp(type, "VOL1", 4) == 0) {
+	} else if ((strncmp(type, "VOL1", 4) == 0) &&
+		(!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
 		/*
 		 * New style VOL1 labeled disk
 		 */
