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

 - Adapt to notify api change in cio.
 - Add missing unregister_reboot_notifier() for error path.
 - Fix infinite error recovery escalation for certain port failures.
 - Fix reference counting.
 - Use GFP_ATOMIC for kmalloc while holding a spinlock.
 - Don't open adapter/port if unit/port is removed from configuration
   after it has already been closed.
 - Don't establish qdio queues if a port/unit is going to be removed.
 - Shutdown ports and units before removing them. 
 - Use schedule_work for scsi_add_device.
 - Don't reopen nameserver port when an rscn was received.
 - Don't call scsi_done twice in zfcp_fsf_send_fcp_command_task_handler.
 - Get rid of scsi fake queue, scsi_reqs_active and scsi_reqs_active_wq.
 - Get rid of unused adapter status.
 - Allow enabling of scsi devices at boot time with zfcp_dev parameter.
 - Change name prefix from sg to sg_list for functions which work with
   the struct sg_list.
 - Don't call scsi_add_device from zfcp error recovery thread to avoid a
   deadlock if a scsi command sent during scsi_add_device fails.
 - Fix scsi i/o stall due to missing local-link-up event.



---

 25-akpm/drivers/s390/scsi/zfcp_aux.c           |  191 +++++++++++++-------
 25-akpm/drivers/s390/scsi/zfcp_ccw.c           |   14 -
 25-akpm/drivers/s390/scsi/zfcp_def.h           |   27 +-
 25-akpm/drivers/s390/scsi/zfcp_erp.c           |  132 ++++++++++++--
 25-akpm/drivers/s390/scsi/zfcp_ext.h           |   10 -
 25-akpm/drivers/s390/scsi/zfcp_fsf.c           |  122 +++++++------
 25-akpm/drivers/s390/scsi/zfcp_fsf.h           |    3 
 25-akpm/drivers/s390/scsi/zfcp_qdio.c          |   52 +++--
 25-akpm/drivers/s390/scsi/zfcp_scsi.c          |  228 ++-----------------------
 25-akpm/drivers/s390/scsi/zfcp_sysfs_adapter.c |   12 -
 25-akpm/drivers/s390/scsi/zfcp_sysfs_port.c    |   28 ++-
 25-akpm/drivers/s390/scsi/zfcp_sysfs_unit.c    |   14 +
 12 files changed, 431 insertions(+), 402 deletions(-)

diff -puN drivers/s390/scsi/zfcp_aux.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_aux.c
--- 25/drivers/s390/scsi/zfcp_aux.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_aux.c	Thu Jan  8 14:11:34 2004
@@ -28,7 +28,7 @@
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_AUX_REVISION "$Revision: 1.65 $"
+#define ZFCP_AUX_REVISION "$Revision: 1.79 $"
 
 /********************** INCLUDES *********************************************/
 
@@ -285,7 +285,7 @@ zfcp_cmd_dbf_event_scsi(const char *text
 	debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32));
 	debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
 		    sizeof (unsigned long));
-	if (fsf_req) {
+	if (likely(fsf_req)) {
 		debug_event(adapter->cmd_dbf, level, &fsf_req,
 			    sizeof (unsigned long));
 		debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,
@@ -316,6 +316,89 @@ zfcp_in_els_dbf_event(struct zfcp_adapte
 #endif
 }
 
+#ifndef MODULE
+/**
+ * zfcp_device_setup - setup function
+ * @str: pointer to parameter string
+ *
+ * Parse the kernel parameter string "zfcp_device=..."
+ */
+static int __init
+zfcp_device_setup(char *str)
+{
+	char *tmp;
+
+	tmp = strchr(str, ',');
+	if (!tmp)
+		goto err_out;
+	*tmp++ = '\0';
+	strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE);
+	zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0';
+
+	zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0);
+	if (*tmp++ != ',')
+		goto err_out;
+	if (*tmp == '\0')
+		goto err_out;
+
+	zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0);
+	if (*tmp != '\0')
+		goto err_out;
+
+	zfcp_data.init_is_valid = 1;
+	goto out;
+
+ err_out:
+	ZFCP_LOG_NORMAL("Parse error for parameter string %s\n", str);
+ out:
+	return 1;
+}
+
+__setup("zfcp_device=", zfcp_device_setup);
+
+static void __init
+zfcp_init_device_configure(void)
+{
+	int found = 0;
+	unsigned long flags;
+	struct zfcp_adapter *adapter;
+	struct zfcp_port *port;
+	struct zfcp_unit *unit;
+
+	down(&zfcp_data.config_sema);
+	read_lock_irqsave(&zfcp_data.config_lock, flags);
+	list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
+		if (strcmp(zfcp_data.init_busid,
+			   zfcp_get_busid_by_adapter(adapter)) == 0) {
+			zfcp_adapter_get(adapter);
+			found = 1;
+			break;
+		}
+	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	if (!found)
+		goto out_adapter;
+	port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0);
+	if (!port)
+		goto out_port;
+	unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun);
+	if (!unit)
+		goto out_unit;
+	up(&zfcp_data.config_sema);
+	ccw_device_set_online(adapter->ccw_device);
+	down(&zfcp_data.config_sema);
+	wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0);
+	zfcp_unit_put(unit);
+ out_unit:
+	zfcp_port_put(port);
+ out_port:
+	zfcp_adapter_put(adapter);
+ out_adapter:
+	up(&zfcp_data.config_sema);
+	return;
+}
+
+#endif  /* #ifndef MODULE */
+
 static int __init
 zfcp_module_init(void)
 {
@@ -357,9 +440,15 @@ zfcp_module_init(void)
 		ZFCP_LOG_NORMAL("Registering with common I/O layer failed.\n");
 		goto out_ccw_register;
 	}
+#ifndef MODULE
+	if (zfcp_data.init_is_valid)
+		zfcp_init_device_configure();
+#endif
+
 	goto out;
 
  out_ccw_register:
+	unregister_reboot_notifier(&zfcp_data.reboot_notifier);
 #ifdef ZFCP_STAT_REQSIZES
 	zfcp_statistics_clear_all();
 #endif
@@ -391,13 +480,8 @@ int
 zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code,
 		    void *ptr)
 {
-	int retval = NOTIFY_DONE;
-
-	/* block access to config (for rest of lifetime of this Linux) */
-	down(&zfcp_data.config_sema);
-	zfcp_erp_adapter_shutdown_all();
-
-	return retval;
+	zfcp_ccw_unregister();
+	return NOTIFY_DONE;
 }
 
 #undef ZFCP_LOG_AREA
@@ -503,6 +587,7 @@ zfcp_unit_enqueue(struct zfcp_port *port
 		return NULL;
 	memset(unit, 0, sizeof (struct zfcp_unit));
 
+	init_waitqueue_head(&unit->scsi_add_wq);
 	/* initialise reference count stuff */
 	atomic_set(&unit->refcount, 0);
 	init_waitqueue_head(&unit->remove_wq);
@@ -571,6 +656,7 @@ zfcp_unit_enqueue(struct zfcp_port *port
 	write_unlock_irq(&zfcp_data.config_lock);
 
 	port->units++;
+	zfcp_port_get(port);
 
 	return unit;
 }
@@ -763,17 +849,10 @@ zfcp_adapter_enqueue(struct ccw_device *
 	/* initialize abort lock */
 	rwlock_init(&adapter->abort_lock);
 
-	/* initialise scsi faking structures */
-	rwlock_init(&adapter->fake_list_lock);
-	init_timer(&adapter->fake_scsi_timer);
-
 	/* initialise some erp stuff */
 	init_waitqueue_head(&adapter->erp_thread_wqh);
 	init_waitqueue_head(&adapter->erp_done_wqh);
 
-	/* notification when there are no outstanding SCSI commands */
-	init_waitqueue_head(&adapter->scsi_reqs_active_wq);
-
 	/* initialize lock of associated request queue */
 	rwlock_init(&adapter->request_queue.queue_lock);
 
@@ -904,7 +983,6 @@ zfcp_adapter_enqueue(struct ccw_device *
 	/* put allocated adapter at list tail */
 	write_lock_irq(&zfcp_data.config_lock);
 	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
-	atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &adapter->status);
 	list_add_tail(&adapter->list, &zfcp_data.adapter_list_head);
 	write_unlock_irq(&zfcp_data.config_lock);
 
@@ -1149,6 +1227,7 @@ zfcp_port_enqueue(struct zfcp_adapter *a
 	write_unlock_irq(&zfcp_data.config_lock);
 
 	adapter->ports++;
+	zfcp_adapter_get(adapter);
 
 	return port;
 }
@@ -1193,7 +1272,6 @@ zfcp_nameserver_enqueue(struct zfcp_adap
 	/* set special D_ID */
 	port->d_id = ZFCP_DID_NAMESERVER;
 	adapter->nameserver_port = port;
-	zfcp_adapter_get(adapter);
 	zfcp_port_put(port);
 
 	return 0;
@@ -1216,9 +1294,9 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a
 	struct fcp_rscn_head *fcp_rscn_head;
 	struct fcp_rscn_element *fcp_rscn_element;
 	struct zfcp_port *port;
-	int i;
-	int reopen_unknown = 0;
-	int no_entries;
+	u16 i;
+	u16 no_entries;
+	u32 range_mask;
 	unsigned long flags;
 
 	fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload;
@@ -1232,56 +1310,57 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a
 
 	debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:");
 	for (i = 1; i < no_entries; i++) {
-		int known;
-		int range_mask;
-		int no_notifications;
-
-		range_mask = 0;
-		no_notifications = 0;
-		known = 0;
 		/* skip head and start with 1st element */
 		fcp_rscn_element++;
 		switch (fcp_rscn_element->addr_format) {
 		case ZFCP_PORT_ADDRESS:
 			ZFCP_LOG_FLAGS(1, "ZFCP_PORT_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_PORT;
-			no_notifications = 1;
 			break;
 		case ZFCP_AREA_ADDRESS:
 			ZFCP_LOG_FLAGS(1, "ZFCP_AREA_ADDRESS\n");
-			/* skip head and start with 1st element */
 			range_mask = ZFCP_PORTS_RANGE_AREA;
-			no_notifications = ZFCP_NO_PORTS_PER_AREA;
 			break;
 		case ZFCP_DOMAIN_ADDRESS:
 			ZFCP_LOG_FLAGS(1, "ZFCP_DOMAIN_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_DOMAIN;
-			no_notifications = ZFCP_NO_PORTS_PER_DOMAIN;
 			break;
 		case ZFCP_FABRIC_ADDRESS:
 			ZFCP_LOG_FLAGS(1, "ZFCP_FABRIC_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_FABRIC;
-			no_notifications = ZFCP_NO_PORTS_PER_FABRIC;
 			break;
 		default:
-			/* cannot happen */
-			break;
+			ZFCP_LOG_INFO("Received RSCN with unknown "
+				      "address format.\n");
+			continue;
 		}
 		read_lock_irqsave(&zfcp_data.config_lock, flags);
 		list_for_each_entry(port, &adapter->port_list_head, list) {
+			if (atomic_test_mask
+			    (ZFCP_STATUS_PORT_NAMESERVER, &port->status))
+				continue;
 			/* Do we know this port? If not skip it. */
 			if (!atomic_test_mask
-			    (ZFCP_STATUS_PORT_DID_DID, &port->status))
+			    (ZFCP_STATUS_PORT_DID_DID, &port->status)) {
+				ZFCP_LOG_INFO
+					("Received state change notification."
+					 "Trying to open the port with wwpn "
+					 "0x%Lx. Hope it's there now.\n",
+					 port->wwpn);
+				debug_text_event(adapter->erp_dbf, 1,
+						 "unsol_els_rscnu:");
+				zfcp_erp_port_reopen(port,
+						     ZFCP_STATUS_COMMON_ERP_FAILED);
 				continue;
+			}
+
 			/*
 			 * FIXME: race: d_id might being invalidated
 			 * (...DID_DID reset)
 			 */
 			if ((port->d_id & range_mask)
 			    == (fcp_rscn_element->nport_did & range_mask)) {
-				known++;
-				ZFCP_LOG_TRACE("known=%d, reopen did 0x%x\n",
-					       known,
+				ZFCP_LOG_TRACE("reopen did 0x%x\n",
 					       fcp_rscn_element->nport_did);
 				/*
 				 * Unfortunately, an RSCN does not specify the
@@ -1303,36 +1382,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a
 			}
 		}
 		read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-		ZFCP_LOG_TRACE("known %d, no_notifications %d\n",
-			       known, no_notifications);
-		if (known < no_notifications) {
-			ZFCP_LOG_DEBUG
-			    ("At least one unknown port changed state. "
-			     "Unknown ports need to be reopened.\n");
-			reopen_unknown = 1;
-		}
-	}			// for (i=1; i < no_entries; i++)
-
-	if (reopen_unknown) {
-		ZFCP_LOG_DEBUG("At least one unknown did "
-			       "underwent a state change.\n");
-		read_lock_irqsave(&zfcp_data.config_lock, flags);
-		list_for_each_entry(port, &adapter->port_list_head, list) {
-			if (!atomic_test_mask((ZFCP_STATUS_PORT_DID_DID
-					       | ZFCP_STATUS_PORT_NAMESERVER),
-					      &port->status)) {
-				ZFCP_LOG_INFO
-				    ("Received state change notification."
-				     "Trying to open the port with wwpn "
-				     "0x%Lx. Hope it's there now.\n",
-				     port->wwpn);
-				debug_text_event(adapter->erp_dbf, 1,
-						 "unsol_els_rscnu:");
-				zfcp_erp_port_reopen(port,
-						     ZFCP_STATUS_COMMON_ERP_FAILED);
-			}
-		}
-		read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 	}
 }
 
@@ -1469,7 +1518,7 @@ zfcp_get_nameserver_buffers(struct zfcp_
 	struct zfcp_adapter *adapter = fsf_req->adapter;
 	int retval = 0;
 
-	data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_KERNEL);
+	data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC);
 	if (data->outbuf) {
 		memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
 	} else {
@@ -1479,7 +1528,7 @@ zfcp_get_nameserver_buffers(struct zfcp_
 			       "adapter %s directly.. trying emergency pool\n",
 			       zfcp_get_busid_by_adapter(adapter));
 		data->outbuf =
-		    mempool_alloc(adapter->pool.nameserver, GFP_KERNEL);
+		    mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC);
 		if (!data->outbuf) {
 			ZFCP_LOG_DEBUG
 				("Out of memory. Could not get emergency "
diff -puN drivers/s390/scsi/zfcp_ccw.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_ccw.c
--- 25/drivers/s390/scsi/zfcp_ccw.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_ccw.c	Thu Jan  8 14:11:34 2004
@@ -25,7 +25,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_CCW_C_REVISION "$Revision: 1.33 $"
+#define ZFCP_CCW_C_REVISION "$Revision: 1.36 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -37,7 +37,7 @@
 #define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_CONFIG
 
 static int zfcp_ccw_probe(struct ccw_device *);
-static int zfcp_ccw_remove(struct ccw_device *);
+static void zfcp_ccw_remove(struct ccw_device *);
 static int zfcp_ccw_set_online(struct ccw_device *);
 static int zfcp_ccw_set_offline(struct ccw_device *);
 
@@ -90,16 +90,17 @@ zfcp_ccw_probe(struct ccw_device *ccw_de
  *
  * This function gets called by the common i/o layer and removes an adapter
  * from the system. Task of this function is to get rid of all units and
- * ports that belong to this adapter. And addition all resources of this
+ * ports that belong to this adapter. And in addition all resources of this
  * adapter will be freed too.
  */
-static int
+static void
 zfcp_ccw_remove(struct ccw_device *ccw_device)
 {
 	struct zfcp_adapter *adapter;
 	struct zfcp_port *port, *p;
 	struct zfcp_unit *unit, *u;
 
+	ccw_device_set_offline(ccw_device);
 	down(&zfcp_data.config_sema);
 	adapter = dev_get_drvdata(&ccw_device->dev);
 
@@ -119,16 +120,18 @@ zfcp_ccw_remove(struct ccw_device *ccw_d
 	list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) {
 		list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) {
 			zfcp_unit_wait(unit);
+			zfcp_sysfs_unit_remove_files(&unit->sysfs_device);
 			device_unregister(&unit->sysfs_device);
 		}
 		zfcp_port_wait(port);
+		zfcp_sysfs_port_remove_files(&port->sysfs_device,
+					     atomic_read(&port->status));
 		device_unregister(&port->sysfs_device);
 	}
 	zfcp_adapter_wait(adapter);
 	zfcp_adapter_dequeue(adapter);
 
 	up(&zfcp_data.config_sema);
-	return 0;
 }
 
 /**
@@ -155,6 +158,7 @@ zfcp_ccw_set_online(struct ccw_device *c
 	zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
 				       ZFCP_SET);
 	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
+	zfcp_erp_wait(adapter);
  out:
 	up(&zfcp_data.config_sema);
 	return retval;
diff -puN drivers/s390/scsi/zfcp_def.h~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_def.h
--- 25/drivers/s390/scsi/zfcp_def.h~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_def.h	Thu Jan  8 14:11:34 2004
@@ -31,10 +31,8 @@
 #ifndef ZFCP_DEF_H
 #define ZFCP_DEF_H
 
-#ifdef __KERNEL__
-
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_DEF_REVISION "$Revision: 1.41 $"
+#define ZFCP_DEF_REVISION "$Revision: 1.48 $"
 
 /*************************** INCLUDES *****************************************/
 
@@ -64,7 +62,6 @@
 typedef u32 scsi_id_t;
 typedef u32 scsi_lun_t;
 
-#define ZFCP_FAKE_SCSI_COMPLETION_TIME	        (HZ / 3)
 #define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT           (100*HZ)
 #define ZFCP_SCSI_ER_TIMEOUT                    (100*HZ)
 #define ZFCP_SCSI_HOST_FLUSH_TIMEOUT            (1*HZ)
@@ -470,7 +467,6 @@ extern u32 flags_dump;
 #define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL	0x00000080
 #define ZFCP_STATUS_ADAPTER_ERP_PENDING		0x00000100
 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED	0x00000200
-#define ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK	0x00000400 
 
 #define ZFCP_STATUS_ADAPTER_SCSI_UP			\
 		(ZFCP_STATUS_COMMON_UNBLOCKED |	\
@@ -676,10 +672,7 @@ struct zfcp_adapter {
 	u32			hydra_version;	   /* Hydra version */
 	u32			fsf_lic_version;
 	struct Scsi_Host	*scsi_host;	   /* Pointer to mid-layer */
-        Scsi_Cmnd               *first_fake_cmnd;  /* Packets in flight list */
-	rwlock_t		fake_list_lock;    /* Lock for the above */
-	struct timer_list       fake_scsi_timer;   /* Starts processing of
-						      faked commands */
+
 	unsigned char		name[9];
 	struct list_head	port_list_head;	   /* remote port list */
 	struct list_head        port_remove_lh;    /* head of ports to be
@@ -692,9 +685,6 @@ struct zfcp_adapter {
 	rwlock_t		fsf_req_list_lock; /* lock for ops on list of
 						      FSF requests */
         atomic_t       		fsf_reqs_active;   /* # active FSF reqs */
-        atomic_t       		scsi_reqs_active;  /* # active SCSI reqs */
-	wait_queue_head_t	scsi_reqs_active_wq; /* can be used to wait for
-							fsf_reqs_active chngs */
 	struct zfcp_qdio_queue	request_queue;	   /* request queue */
 	u32			fsf_req_seq_no;	   /* FSF cmnd seq number */
 	wait_queue_head_t	request_wq;	   /* can be used to wait for
@@ -765,6 +755,8 @@ struct zfcp_unit {
 	struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
 	struct device          sysfs_device;   /* sysfs device */
+	atomic_t               scsi_add_work;  /* used to synchronize */
+	wait_queue_head_t      scsi_add_wq;    /* wait for scsi_add_device */
 };
 
 /* FSF request */
@@ -809,6 +801,14 @@ struct zfcp_data {
 	struct notifier_block	reboot_notifier;     /* used to register cleanup
 							functions */
 	atomic_t		loglevel;            /* current loglevel */
+#ifndef MODULE                                       /* initial parameters
+							needed if ipl from a
+							scsi device is wanted */
+	char                    init_busid[BUS_ID_SIZE];
+	wwn_t                   init_wwpn;
+	fcp_lun_t               init_fcp_lun;
+	int                     init_is_valid;
+#endif
 #ifdef ZFCP_STAT_REQSIZES                            /* Statistical accounting
 							of processed data */
 	struct list_head	read_req_head;
@@ -857,7 +857,7 @@ struct zfcp_statistics {
 
 #ifndef atomic_test_mask
 #define atomic_test_mask(mask, target) \
-           (atomic_read(target) & mask)
+           ((atomic_read(target) & mask) == mask)
 #endif
 
 extern void _zfcp_hex_dump(char *, int);
@@ -957,5 +957,4 @@ zfcp_adapter_wait(struct zfcp_adapter *a
 	wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
 }
 
-#endif /* __KERNEL_- */
 #endif /* ZFCP_DEF_H */
diff -puN drivers/s390/scsi/zfcp_erp.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_erp.c
--- 25/drivers/s390/scsi/zfcp_erp.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_erp.c	Thu Jan  8 14:11:34 2004
@@ -30,7 +30,7 @@
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_ERP
 #define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_ERP
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_ERP_REVISION "$Revision: 1.33 $"
+#define ZFCP_ERP_REVISION "$Revision: 1.39 $"
 
 #include "zfcp_ext.h"
 
@@ -108,6 +108,9 @@ static int zfcp_erp_action_dismiss(struc
 static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *,
 				   struct zfcp_port *, struct zfcp_unit *);
 static int zfcp_erp_action_dequeue(struct zfcp_erp_action *);
+static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
+				    struct zfcp_port *, struct zfcp_unit *,
+				    int);
 
 static void zfcp_erp_action_ready(struct zfcp_erp_action *);
 static int  zfcp_erp_action_exists(struct zfcp_erp_action *);
@@ -1160,6 +1163,9 @@ zfcp_erp_strategy(struct zfcp_erp_action
 	write_unlock(&adapter->erp_lock);
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 	
+	if (retval != ZFCP_ERP_CONTINUES)
+		zfcp_erp_action_cleanup(action, adapter, port, unit, retval);
+
 	/*
 	 * a few tasks remain when the erp queues are empty
 	 * (don't do that if the last action evaluated was dismissed
@@ -1451,6 +1457,66 @@ zfcp_erp_strategy_statechange_detected(a
 	     !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status));
 }
 
+/**
+ * zfcp_erp_scsi_add_device
+ * @data: pointer to a struct zfcp_unit
+ *
+ * Registers a logical unit with the SCSI stack.
+ */
+static void
+zfcp_erp_scsi_add_device(void *data)
+{
+	struct {
+		struct zfcp_unit  *unit;
+		struct work_struct work;
+	} *p;
+
+	p = data;
+	scsi_add_device(p->unit->port->adapter->scsi_host,
+			0, p->unit->port->scsi_id, p->unit->scsi_lun);
+	atomic_set(&p->unit->scsi_add_work, 0);
+	wake_up(&p->unit->scsi_add_wq);
+	zfcp_unit_put(p->unit);
+	kfree(p);
+}
+
+/**
+ * zfcp_erp_schedule_work
+ * @unit: pointer to unit which should be registered with SCSI stack
+ *
+ * Schedules work which registers a unit with the SCSI stack
+ */
+static int
+zfcp_erp_schedule_work(struct zfcp_unit *unit)
+{
+	struct {
+		struct zfcp_unit * unit;
+		struct work_struct work;
+	} *p;
+
+	if (atomic_compare_and_swap(0, 1, &unit->scsi_add_work))
+		return 0;
+
+	if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) {
+		ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
+			      "the FCP-LUN 0x%Lx connected to "
+			      "the port with WWPN 0x%Lx connected to "
+			      "the adapter %s with the SCSI stack.\n",
+			      unit->fcp_lun,
+			      unit->port->wwpn,
+			      zfcp_get_busid_by_unit(unit));
+		atomic_set(&p->unit->scsi_add_work, 0);
+		return -ENOMEM;
+	}
+
+	zfcp_unit_get(unit);
+	memset(p, 0, sizeof(*p));
+	INIT_WORK(&p->work, zfcp_erp_scsi_add_device, p);
+	p->unit = unit;
+	schedule_work(&p->work);
+	return 0;
+}
+
 /*
  * function:	
  *
@@ -1468,10 +1534,6 @@ zfcp_erp_strategy_check_unit(struct zfcp
 	if (result == ZFCP_ERP_SUCCEEDED) {
 		atomic_set(&unit->erp_counter, 0);
 		zfcp_erp_unit_unblock(unit);
-		/* register unit with scsi stack */
-		if (!unit->device)
-			scsi_add_device(unit->port->adapter->scsi_host,
-					0, unit->port->scsi_id, unit->scsi_lun);
 	} else {
 		/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
 		atomic_inc(&unit->erp_counter);
@@ -1773,9 +1835,8 @@ zfcp_erp_port_reopen_all_internal(struct
 	struct zfcp_port *port;
 
 	list_for_each_entry(port, &adapter->port_list_head, list)
-	    if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status)
-		!= ZFCP_STATUS_PORT_NAMESERVER)
-		zfcp_erp_port_reopen_internal(port, clear_mask);
+		if (!atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status))
+			zfcp_erp_port_reopen_internal(port, clear_mask);
 
 	return retval;
 }
@@ -2333,8 +2394,8 @@ zfcp_erp_port_forced_strategy(struct zfc
 		 * open flag is unset - however, this is for readabilty ...
 		 */
 		if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN |
-				      ZFCP_STATUS_COMMON_OPEN), &port->status)
-		    == (ZFCP_STATUS_PORT_PHYS_OPEN | ZFCP_STATUS_COMMON_OPEN)) {
+				      ZFCP_STATUS_COMMON_OPEN),
+			             &port->status)) {
 			ZFCP_LOG_DEBUG("Port wwpn=0x%Lx is open -> trying "
 				       " close physical\n",
 				       port->wwpn);
@@ -2433,8 +2494,7 @@ zfcp_erp_port_strategy_open(struct zfcp_
 	int retval;
 
 	if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER,
-			     &erp_action->port->status)
-	    == ZFCP_STATUS_PORT_NAMESERVER)
+			     &erp_action->port->status))
 		retval = zfcp_erp_port_strategy_open_nameserver(erp_action);
 	else
 		retval = zfcp_erp_port_strategy_open_common(erp_action);
@@ -3041,6 +3101,12 @@ zfcp_erp_action_enqueue(int action,
 			goto out;
 		}
 		if (!atomic_test_mask
+		    (ZFCP_STATUS_COMMON_RUNNING, &port->status) ||
+		    atomic_test_mask
+		    (ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
+			goto out;
+		}
+		if (!atomic_test_mask
 		    (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) {
 			stronger_action = ZFCP_ERP_ACTION_REOPEN_PORT;
 			unit = NULL;
@@ -3068,6 +3134,12 @@ zfcp_erp_action_enqueue(int action,
 			goto out;
 		}
 		if (!atomic_test_mask
+		    (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) ||
+		    atomic_test_mask
+		    (ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) {
+			goto out;
+		}
+		if (!atomic_test_mask
 		    (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) {
 			stronger_action = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
 			port = NULL;
@@ -3178,18 +3250,15 @@ zfcp_erp_action_dequeue(struct zfcp_erp_
 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
 				  &erp_action->unit->status);
-		zfcp_unit_put(erp_action->unit);
 		break;
 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
 	case ZFCP_ERP_ACTION_REOPEN_PORT:
 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
 				  &erp_action->port->status);
-		zfcp_port_put(erp_action->port);
 		break;
 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
 				  &erp_action->adapter->status);
-		zfcp_adapter_put(adapter);
 		break;
 	default:
 		/* bug */
@@ -3198,6 +3267,39 @@ zfcp_erp_action_dequeue(struct zfcp_erp_
 	return retval;
 }
 
+/**
+ * zfcp_erp_action_cleanup
+ *
+ * registers unit with scsi stack if appropiate and fixes reference counts
+ */
+
+static void
+zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
+			struct zfcp_port *port, struct zfcp_unit *unit,
+			int result)
+{
+	if ((action == ZFCP_ERP_ACTION_REOPEN_UNIT)
+	    && (result == ZFCP_ERP_SUCCEEDED)
+	    && (!unit->device)) {
+		zfcp_erp_schedule_work(unit);
+	}
+	switch (action) {
+	case ZFCP_ERP_ACTION_REOPEN_UNIT:
+		zfcp_unit_put(unit);
+		break;
+	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+	case ZFCP_ERP_ACTION_REOPEN_PORT:
+		zfcp_port_put(port);
+		break;
+	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+		zfcp_adapter_put(adapter);
+		break;
+	default:
+		break;
+	}
+}
+
+
 /*
  * function:	
  *
diff -puN drivers/s390/scsi/zfcp_ext.h~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_ext.h
--- 25/drivers/s390/scsi/zfcp_ext.h~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_ext.h	Thu Jan  8 14:11:34 2004
@@ -30,9 +30,7 @@
 #ifndef ZFCP_EXT_H
 #define ZFCP_EXT_H
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_EXT_REVISION "$Revision: 1.33 $"
-
-#ifdef __KERNEL__
+#define ZFCP_EXT_REVISION "$Revision: 1.38 $"
 
 #include "zfcp_def.h"
 
@@ -44,7 +42,9 @@ extern void zfcp_sysfs_driver_remove_fil
 extern int  zfcp_sysfs_adapter_create_files(struct device *);
 extern void zfcp_sysfs_adapter_remove_files(struct device *);
 extern int  zfcp_sysfs_port_create_files(struct device *, u32);
+extern void zfcp_sysfs_port_remove_files(struct device *, u32);
 extern int  zfcp_sysfs_unit_create_files(struct device *);
+extern void zfcp_sysfs_unit_remove_files(struct device *);
 extern void zfcp_sysfs_port_release(struct device *);
 extern int  zfcp_sysfs_port_shutdown(struct zfcp_port *);
 extern void zfcp_sysfs_unit_release(struct device *);
@@ -112,9 +112,6 @@ extern void zfcp_fsf_els_processing(stru
 extern int  zfcp_adapter_scsi_register(struct zfcp_adapter *);
 extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
 extern void zfcp_scsi_block_requests(struct Scsi_Host *);
-extern void zfcp_scsi_insert_into_fake_queue(struct zfcp_adapter *,
-					     Scsi_Cmnd *);
-extern void zfcp_scsi_process_and_clear_fake_queue(unsigned long);
 extern int  zfcp_create_sbals_from_sg(struct zfcp_fsf_req *,
 				     Scsi_Cmnd *, char, int, int);
 extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
@@ -159,5 +156,4 @@ extern void zfcp_in_els_dbf_event(struct
 #ifdef ZFCP_STAT_REQSIZES
 extern int  zfcp_statistics_inc(struct list_head *, u32);
 #endif
-#endif	/* __KERNEL__ */
 #endif	/* ZFCP_EXT_H */
diff -puN drivers/s390/scsi/zfcp_fsf.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_fsf.c
--- 25/drivers/s390/scsi/zfcp_fsf.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_fsf.c	Thu Jan  8 14:11:34 2004
@@ -28,7 +28,7 @@
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_FSF_C_REVISION "$Revision: 1.12 $"
+#define ZFCP_FSF_C_REVISION "$Revision: 1.16 $"
 
 #include "zfcp_ext.h"
 
@@ -101,7 +101,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *
 	case FSF_QTCB_ABORT_FCP_CMND:
 		fsf_req = zfcp_fsf_req_get(kmalloc_flags,
 					   adapter->pool.fcp_command_fsf);
-		if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) {
+		if (unlikely(fsf_req &&
+		             (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))) {
 			/*
 			 * watch low mem buffer
 			 * Note: If the command is reset or aborted, two
@@ -116,7 +117,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *
 		}
 #ifdef ZFCP_DEBUG_REQUESTS
 		debug_text_event(adapter->req_dbf, 5, "fsfa_fcp");
-		if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))
+		if (unlikely(fsf_req &&
+		             (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)))
 			debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
 #endif /* ZFCP_DEBUG_REQUESTS */
 		break;
@@ -158,7 +160,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *
 				"(debug info 0x%x)\n", fsf_cmd);
 	}			//switch(fsf_cmd)
 
-	if (!fsf_req) {
+	if (unlikely(!fsf_req)) {
 		ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF "
 			       "request structure failed\n");
 	} else {
@@ -171,7 +173,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *
 
 #ifdef ZFCP_DEBUG_REQUESTS
 	debug_event(adapter->req_dbf, 5, &fsf_req, sizeof (unsigned long));
-	if (fsf_req->qtcb)
+	if (likely(fsf_req->qtcb))
 		debug_event(adapter->req_dbf, 5, &fsf_req->qtcb,
 			    sizeof (unsigned long));
 #endif				/* ZFCP_DEBUG_REQUESTS */
@@ -198,7 +200,7 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *f
 
 	case FSF_QTCB_FCP_CMND:
 	case FSF_QTCB_ABORT_FCP_CMND:
-		if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL) {
+		if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) {
 			del_timer(&adapter->pool.fcp_command_fsf_timer);
 			mempool_free(fsf_req, adapter->pool.fcp_command_fsf);
 		} else
@@ -299,7 +301,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re
 	/* do some statistics */
 	atomic_dec(&adapter->fsf_reqs_active);
 
-	if (fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS) {
+	if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
 		ZFCP_LOG_DEBUG("Status read response received\n");
 		/*
 		 * Note: all cleanup handling is done in the callchain of
@@ -314,7 +316,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re
 	 * fsf_req may be deleted due to waking up functions, so 
 	 * cleanup is saved here and used later 
 	 */
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)
+	if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
 		cleanup = 1;
 	else
 		cleanup = 0;
@@ -322,7 +324,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re
 	fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
 
 	/* cleanup request if requested by initiator */
-	if (cleanup) {
+	if (likely(cleanup)) {
 		ZFCP_LOG_TRACE("removing FSF request 0x%lx\n",
 			       (unsigned long) fsf_req);
 		/*
@@ -334,6 +336,16 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re
 		/* notify initiator waiting for the requests completion */
 		ZFCP_LOG_TRACE("waking initiator of FSF request 0x%lx\n",
 			       (unsigned long) fsf_req);
+		/*
+		 * FIXME: Race! We must not access fsf_req here as it might have been
+		 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
+		 * flag. It's an improbable case. But, we have the same paranoia for
+		 * the cleanup flag already.
+		 * Might better be handled using complete()?
+		 * (setting the flag and doing wakeup ought to be atomic
+		 *  with regard to checking the flag as long as waitqueue is
+		 *  part of the to be released structure)
+		 */
 		wake_up(&fsf_req->completion_wq);
 	}
 
@@ -372,7 +384,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf
 	}
 
 	/* log additional information provided by FSF (if any) */
-	if (fsf_req->qtcb->header.log_length) {
+	if (unlikely(fsf_req->qtcb->header.log_length)) {
 		/* do not trust them ;-) */
 		if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) {
 			ZFCP_LOG_NORMAL
@@ -686,7 +698,7 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_
 {
 	int retval = 0;
 
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
 		goto skip_fsfstatus;
 	}
 
@@ -835,7 +847,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_re
 {
 	int retval = 0;
 
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
 		ZFCP_LOG_TRACE("fsf_req=0x%lx, QTCB=0x%lx\n",
 			       (unsigned long) fsf_req,
 			       (unsigned long) (fsf_req->qtcb));
@@ -1996,6 +2008,20 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
 		retval = 0;
 		/* check whether D_ID has changed during open */
+		/*
+		 * FIXME: This check is not airtight, as the FCP channel does
+		 * not monitor closures of target port connections caused on
+		 * the remote side. Thus, they might miss out on invalidating
+		 * locally cached WWPNs (and other N_Port parameters) of gone
+		 * target ports. So, our heroic attempt to make things safe
+		 * could be undermined by 'open port' response data tagged with
+		 * obsolete WWPNs. Another reason to monitor potential
+		 * connection closures ourself at least (by interpreting
+		 * incoming ELS' and unsolicited status). It just crosses my
+		 * mind that one should be able to cross-check by means of
+		 * another GID_PN straight after a port has been opened.
+		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
+		 */
 		plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els;
 		if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status))
 		{
@@ -2398,9 +2424,9 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio
 	}
 
 	erp_action->fsf_req->qtcb->header.port_handle =
-	    erp_action->port->handle;
-	*(fcp_lun_t *) & (erp_action->fsf_req->qtcb->bottom.support.fcp_lun)
-	    = erp_action->unit->fcp_lun;
+		erp_action->port->handle;
+	erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
+		erp_action->unit->fcp_lun;
 	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
 	erp_action->fsf_req->data.open_unit.unit = erp_action->unit;
 	erp_action->fsf_req->erp_action = erp_action;
@@ -2835,7 +2861,7 @@ zfcp_fsf_send_fcp_command_task(struct zf
 	retval = zfcp_fsf_req_create(adapter,
 				     FSF_QTCB_FCP_CMND,
 				     &lock_flags, req_flags, &(fsf_req));
-	if (retval < 0) {
+	if (unlikely(retval < 0)) {
 		ZFCP_LOG_DEBUG("error: Out of resources. Could not create an "
 			       "FCP command request for FCP-LUN 0x%Lx "
 			       "connected to the port with WWPN 0x%Lx "
@@ -2928,7 +2954,7 @@ zfcp_fsf_send_fcp_command_task(struct zf
 	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
 
 	/* set task attributes in FCP_CMND IU in QTCB */
-	if (scsi_cmnd->device->simple_tags) {
+	if (likely(scsi_cmnd->device->simple_tags)) {
 		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
 		ZFCP_LOG_TRACE("setting SIMPLE_Q task attribute\n");
 	} else {
@@ -2937,7 +2963,7 @@ zfcp_fsf_send_fcp_command_task(struct zf
 	}
 
 	/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
-	if (scsi_cmnd->cmd_len > FCP_CDB_LENGTH) {
+	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) {
 		fcp_cmnd_iu->add_fcp_cdb_length
 		    = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
 		ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, "
@@ -2965,9 +2991,9 @@ zfcp_fsf_send_fcp_command_task(struct zf
 	/* Note: >= and not = because the combined scatter-gather entries
 	 * may be larger than request_bufflen according to the mailing list
 	 */
-	if (real_bytes >= scsi_cmnd->request_bufflen) {
+	if (likely(real_bytes >= scsi_cmnd->request_bufflen)) {
 		ZFCP_LOG_TRACE("Data fits\n");
-	} else if (real_bytes == 0) {
+	} else if (likely(real_bytes == 0)) {
 		ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), "
 			       "waiting for more...\n");
 		retval = -EIO;
@@ -2996,7 +3022,7 @@ zfcp_fsf_send_fcp_command_task(struct zf
 	 *  covered by an SBALE)
 	 */
 	retval = zfcp_fsf_req_send(fsf_req, NULL);
-	if (retval < 0) {
+	if (unlikely(retval < 0)) {
 		ZFCP_LOG_INFO("error: Could not send an FCP command request "
 			      "for a command on the adapter %s, "
 			      "port WWPN 0x%Lx and unit LUN 0x%Lx\n",
@@ -3139,12 +3165,12 @@ zfcp_fsf_send_fcp_command_handler(struct
 	int retval = -EINVAL;
 	struct zfcp_unit *unit;
 
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
+	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
 		unit = fsf_req->data.send_fcp_command_task_management.unit;
 	else
 		unit = fsf_req->data.send_fcp_command_task.unit;
 
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
 		/* go directly to calls of special handlers */
 		goto skip_fsfstatus;
 	}
@@ -3445,7 +3471,6 @@ static int
 zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
 {
 	int retval = 0;
-	struct zfcp_adapter *adapter = fsf_req->adapter;
 
 	Scsi_Cmnd *scpnt;
 	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
@@ -3459,14 +3484,14 @@ zfcp_fsf_send_fcp_command_task_handler(s
 
 	read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
 	scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd;
-	if (!scpnt) {
+	if (unlikely(!scpnt)) {
 		ZFCP_LOG_DEBUG
 		    ("Command with fsf_req 0x%lx is not associated to "
 		     "a scsi command anymore. Aborted?\n",
 		     (unsigned long) fsf_req);
 		goto out;
 	}
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED) {
+	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
 		/* FIXME: (design) mid-layer should handle DID_ABORT like
 		 *        DID_SOFT_ERROR by retrying the request for devices
 		 *        that allow retries.
@@ -3477,7 +3502,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 		goto skip_fsfstatus;
 	}
 
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
 		ZFCP_LOG_DEBUG("Setting DID_ERROR\n");
 		set_host_byte(&scpnt->result, DID_ERROR);
 		goto skip_fsfstatus;
@@ -3491,7 +3516,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 	 * of result in SCSI command
 	 */
 	scpnt->result |= fcp_rsp_iu->scsi_status;
-	if (fcp_rsp_iu->scsi_status) {
+	if (unlikely(fcp_rsp_iu->scsi_status)) {
 		/* DEBUG */
 		ZFCP_LOG_NORMAL("status for SCSI Command:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
@@ -3507,7 +3532,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 	}
 
 	/* check FCP_RSP_INFO */
-	if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) {
+	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
 		ZFCP_LOG_DEBUG("rsp_len is valid\n");
 		switch (fcp_rsp_info[3]) {
 		case RSP_CODE_GOOD:
@@ -3600,7 +3625,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 	}
 
 	/* check for sense data */
-	if (fcp_rsp_iu->validity.bits.fcp_sns_len_valid) {
+	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
 		sns_len = FSF_FCP_RSP_SIZE -
 		    sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
 		ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n",
@@ -3623,7 +3648,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 	}
 
 	/* check for overrun */
-	if (fcp_rsp_iu->validity.bits.fcp_resid_over) {
+	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) {
 		ZFCP_LOG_INFO("A data overrun was detected for a command. "
 			      "This happened for a command to the unit "
 			      "with FCP LUN 0x%Lx connected to the "
@@ -3638,7 +3663,7 @@ zfcp_fsf_send_fcp_command_task_handler(s
 	}
 
 	/* check for underrun */
-	if (fcp_rsp_iu->validity.bits.fcp_resid_under) {
+	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
 		ZFCP_LOG_DEBUG("A data underrun was detected for a command. "
 			       "This happened for a command to the unit "
 			       "with FCP LUN 0x%Lx connected to the "
@@ -3755,9 +3780,6 @@ zfcp_fsf_send_fcp_command_task_handler(s
 	 * the new eh
 	 */
 	/* always call back */
-	(scpnt->scsi_done) (scpnt);
-	atomic_dec(&adapter->scsi_reqs_active);
-	wake_up(&adapter->scsi_reqs_active_wq);
 #ifdef ZFCP_DEBUG_REQUESTS
 	debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:");
 	debug_event(fsf_req->adapter->req_dbf, 2, &scpnt,
@@ -3768,8 +3790,6 @@ zfcp_fsf_send_fcp_command_task_handler(s
 		    sizeof (unsigned long));
 #endif /* ZFCP_DEBUG_REQUESTS */
 	(scpnt->scsi_done) (scpnt);
-	atomic_dec(&adapter->scsi_reqs_active);
-	wake_up(&adapter->scsi_reqs_active_wq);
 	/*
 	 * We must hold this lock until scsi_done has been called.
 	 * Otherwise we may call scsi_done after abort regarding this
@@ -3904,7 +3924,7 @@ zfcp_fsf_req_create_sbal_check(unsigned 
 			       struct zfcp_qdio_queue *queue, int needed)
 {
 	write_lock_irqsave(&queue->queue_lock, *flags);
-	if (atomic_read(&queue->free_count) >= needed)
+	if (likely(atomic_read(&queue->free_count) >= needed))
 		return 1;
 	write_unlock_irqrestore(&queue->queue_lock, *flags);
 	return 0;
@@ -3942,7 +3962,7 @@ zfcp_fsf_req_create(struct zfcp_adapter 
 
 	/* allocate new FSF request */
 	fsf_req = zfcp_fsf_req_alloc(adapter, fsf_cmd, GFP_ATOMIC);
-	if (!fsf_req) {
+	if (unlikely(!fsf_req)) {
 		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
 			       "the outbound (send) queue.\n");
 		retval = -ENOMEM;
@@ -3960,11 +3980,11 @@ zfcp_fsf_req_create(struct zfcp_adapter 
 	fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ;
 
 	fsf_req->fsf_command = fsf_cmd;
-	if (req_flags & ZFCP_REQ_AUTO_CLEANUP)
+	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
 
 	/* initialize QTCB */
-	if (fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS) {
+	if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
 		ZFCP_LOG_TRACE("fsf_req->qtcb=0x%lx\n",
 			       (unsigned long) fsf_req->qtcb);
 		fsf_req->qtcb->prefix.req_id = (unsigned long) fsf_req;
@@ -3983,7 +4003,7 @@ zfcp_fsf_req_create(struct zfcp_adapter 
 	 * try to get needed SBALs in request queue (get queue lock on success)
 	 */
 	ZFCP_LOG_TRACE("try to get free BUFFER in request queue\n");
-	if (req_flags & ZFCP_WAIT_FOR_SBAL) {
+	if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
 		timeout = ZFCP_SBAL_TIMEOUT;
 		ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq,
 					timeout,
@@ -4009,7 +4029,7 @@ zfcp_fsf_req_create(struct zfcp_adapter 
 	/* setup common SBALE fields */
 	buffere[0].addr = fsf_req;
 	buffere[0].flags |= SBAL_FLAGS0_COMMAND;
-	if (fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS) {
+	if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
 		buffere[1].addr = (void *) fsf_req->qtcb;
 		buffere[1].length = ZFCP_QTCB_SIZE;
 	}
@@ -4116,7 +4136,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 		      buffere->length);
 
 	/* set sequence counter in QTCB */
-	if (fsf_req->qtcb) {
+	if (likely(fsf_req->qtcb)) {
 		fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
 		fsf_req->seq_no = adapter->fsf_req_seq_no;
 		ZFCP_LOG_TRACE("FSF request 0x%lx of adapter 0x%lx gets "
@@ -4133,7 +4153,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 	write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
 
 	/* figure out expiration time of timeout and start timeout */
-	if (timer) {
+	if (unlikely(timer)) {
 		timer->expires += jiffies;
 		add_timer(timer);
 	}
@@ -4167,7 +4187,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 			 QDIO_FLAG_SYNC_OUTPUT,
 			 0, fsf_req->sbal_index, fsf_req->sbal_count, NULL);
 
-	if (retval) {
+	if (unlikely(retval)) {
 		/* Queues are down..... */
 		retval = -EIO;
 		/*
@@ -4198,7 +4218,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 		debug_text_event(adapter->req_dbf, 1, "o:a/seq");
 		debug_event(adapter->req_dbf, 1, &fsf_req,
 			    sizeof (unsigned long));
-		if (inc_seq_no) {
+		if (likely(inc_seq_no)) {
 			debug_event(adapter->req_dbf, 1,
 				    &adapter->fsf_req_seq_no, sizeof (u32));
 		} else {
@@ -4213,7 +4233,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 		 * otherwise,
 		 */
 		/* Don't increase for unsolicited status */
-		if (inc_seq_no) {
+		if (likely(inc_seq_no)) {
 			adapter->fsf_req_seq_no++;
 			ZFCP_LOG_TRACE
 			    ("FSF sequence counter value of adapter 0x%lx "
@@ -4263,16 +4283,16 @@ zfcp_fsf_req_get(int kmalloc_flags, memp
 	struct zfcp_fsf_req *fsf_req;
 
 	fsf_req = kmalloc(ZFCP_QTCB_AND_REQ_SIZE, kmalloc_flags);
-	if (fsf_req) {
+	if (likely(fsf_req)) {
 		memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
 	} else {
 		fsf_req = mempool_alloc(pool, kmalloc_flags);
-		if (fsf_req) {
+		if (likely(fsf_req)) {
 			memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
 			fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
 		}
 	}
-	if (fsf_req)
+	if (likely(fsf_req))
 		fsf_req->qtcb =
 		    (struct fsf_qtcb *) ((unsigned long) fsf_req +
 					 sizeof (struct zfcp_fsf_req));
diff -puN drivers/s390/scsi/zfcp_fsf.h~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_fsf.h
--- 25/drivers/s390/scsi/zfcp_fsf.h~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_fsf.h	Thu Jan  8 14:11:34 2004
@@ -30,8 +30,6 @@
 #ifndef FSF_H
 #define FSF_H
 
-#ifdef __KERNEL__
-
 #define FSF_QTCB_VERSION1			0x00000001
 #define FSF_QTCB_CURRENT_VERSION		FSF_QTCB_VERSION1
 
@@ -354,5 +352,4 @@ struct fsf_qtcb {
 	union  fsf_qtcb_bottom bottom;
 } __attribute__ ((packed));
 
-#endif				/* __KERNEL__ */
 #endif				/* FSF_H */
diff -puN drivers/s390/scsi/zfcp_qdio.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_qdio.c
--- 25/drivers/s390/scsi/zfcp_qdio.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_qdio.c	Thu Jan  8 14:11:34 2004
@@ -27,7 +27,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_QDIO_C_REVISION "$Revision: 1.7 $"
+#define ZFCP_QDIO_C_REVISION "$Revision: 1.10 $"
 
 #include "zfcp_ext.h"
 
@@ -214,7 +214,7 @@ zfcp_qdio_handler_error_check(struct zfc
 				       " QDIO_STATUS_OUTBOUND_INT \n");
 		}
 	}			// if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE))
-	if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
+	if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) {
 		retval = -EIO;
 
 		ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n");
@@ -261,7 +261,17 @@ zfcp_qdio_handler_error_check(struct zfc
 		}
 		/* Restarting IO on the failed adapter from scratch */
 		debug_text_event(adapter->erp_dbf, 1, "qdio_err");
-		zfcp_erp_adapter_reopen(adapter, 0);
+               /*
+                * Since we have been using this adapter, it is save to assume
+                * that it is not failed but recoverable. The card seems to
+                * report link-up events by self-initiated queue shutdown.
+                * That is why we need to clear the the link-down flag
+                * which is set again in case we have missed by a mile.
+                */
+               zfcp_erp_adapter_reopen(
+                       adapter, 
+                       ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+                       ZFCP_STATUS_COMMON_ERP_FAILED);
 	}
 	return retval;
 }
@@ -293,8 +303,8 @@ zfcp_qdio_request_handler(struct ccw_dev
 		       zfcp_get_busid_by_adapter(adapter),
 		       first_element, elements_processed);
 
-	if (zfcp_qdio_handler_error_check(adapter, status, qdio_error,
-					  siga_error))
+	if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
+					           siga_error)))
 		goto out;
 	/*
 	 * we stored address of struct zfcp_adapter  data structure
@@ -345,8 +355,8 @@ zfcp_qdio_response_handler(struct ccw_de
 	adapter = (struct zfcp_adapter *) int_parm;
 	queue = &adapter->response_queue;
 
-	if (zfcp_qdio_handler_error_check(adapter, status, qdio_error,
-					  siga_error))
+	if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
+					           siga_error)))
 		goto out;
 
 	/*
@@ -394,11 +404,17 @@ zfcp_qdio_response_handler(struct ccw_de
 				ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
 					      (char *) buffer, SBAL_SIZE);
 			}
-			if (buffere->flags & SBAL_FLAGS_LAST_ENTRY)
+			/*
+			 * A single used SBALE per inbound SBALE has been
+			 * implemented by QDIO so far. Hope they will
+			 * do some optimisation. Will need to change to
+			 * unlikely() then.
+			 */
+			if (likely(buffere->flags & SBAL_FLAGS_LAST_ENTRY))
 				break;
 		};
 
-		if (!buffere->flags & SBAL_FLAGS_LAST_ENTRY) {
+		if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) {
 			ZFCP_LOG_NORMAL("bug: End of inbound data "
 					"not marked!\n");
 		}
@@ -421,7 +437,7 @@ zfcp_qdio_response_handler(struct ccw_de
 			 QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT,
 			 0, start, count, NULL);
 
-	if (retval) {
+	if (unlikely(retval)) {
 		atomic_set(&queue->free_count, count);
 		ZFCP_LOG_DEBUG("Inbound data regions could not be cleared "
 			       "Transfer queues may be down. "
@@ -458,7 +474,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 #endif				/* ZFCP_DEBUG_REQUESTS */
 
 	/* invalid (per convention used in this driver) */
-	if (!sbale_addr) {
+	if (unlikely(!sbale_addr)) {
 		ZFCP_LOG_NORMAL
 		    ("bug: Inbound data faulty, contains null-pointer!\n");
 		retval = -EINVAL;
@@ -468,8 +484,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 	/* valid request id and thus (hopefully :) valid fsf_req address */
 	fsf_req = (struct zfcp_fsf_req *) sbale_addr;
 
-	if ((fsf_req->common_magic != ZFCP_MAGIC) ||
-	    (fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ)) {
+	if (unlikely((fsf_req->common_magic != ZFCP_MAGIC) ||
+	             (fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ))) {
 		ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was "
 				"faulty (debug info 0x%x, 0x%x, 0x%lx)\n",
 				fsf_req->common_magic,
@@ -479,7 +495,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 		goto out;
 	}
 
-	if (adapter != fsf_req->adapter) {
+	if (unlikely(adapter != fsf_req->adapter)) {
 		ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was not "
 				"correct (debug info 0x%lx, 0x%lx, 0%lx) \n",
 				(unsigned long) fsf_req,
@@ -490,7 +506,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 	}
 #ifdef ZFCP_DEBUG_REQUESTS
 	/* debug feature stuff (test for QTCB: remember new unsol. status!) */
-	if (fsf_req->qtcb) {
+	if (likely(fsf_req->qtcb)) {
 		debug_event(adapter->req_dbf, 1,
 			    &fsf_req->qtcb->prefix.req_seq_no, sizeof (u32));
 	}
@@ -498,7 +514,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 
 	ZFCP_LOG_TRACE("fsf_req at 0x%lx, QTCB at 0x%lx\n",
 		       (unsigned long) fsf_req, (unsigned long) fsf_req->qtcb);
-	if (fsf_req->qtcb) {
+	if (likely(fsf_req->qtcb)) {
 		ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
 			      (char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
@@ -518,8 +534,8 @@ zfcp_qdio_determine_pci(struct zfcp_qdio
 	int pci_pos;
 
 	new_distance_from_int = req_queue->distance_from_int +
-	    fsf_req->sbal_count;
-	if (new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL) {
+				fsf_req->sbal_count;
+	if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) {
 		new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL;
 		pci_pos = fsf_req->sbal_index;
 		pci_pos += fsf_req->sbal_count;
diff -puN drivers/s390/scsi/zfcp_scsi.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_scsi.c
--- 25/drivers/s390/scsi/zfcp_scsi.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_scsi.c	Thu Jan  8 14:11:34 2004
@@ -30,7 +30,7 @@
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_SCSI
 #define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_SCSI
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_SCSI_REVISION "$Revision: 1.38 $"
+#define ZFCP_SCSI_REVISION "$Revision: 1.42 $"
 
 #include <linux/blkdev.h>
 
@@ -225,99 +225,6 @@ zfcp_scsi_slave_destroy(struct scsi_devi
 	}
 }
 
-/*
- * function:    zfcp_scsi_insert_into_fake_queue
- *
- * purpose:
- *		
- *
- * returns:
- *
- * FIXME:	Is the following scenario possible and - even more interesting -
- *		a problem? It reminds me of the famous 'no retry for tape' fix
- *		(no problem for disks, but what is about tapes...)
- *
- *		device is unaccessable,
- *		command A is put into the fake queue,
- *		device becomes accessable again,
- *		command B is queued to the device,
- *		fake queue timer expires
- *		command A is returned to the mid-layer
- *		command A is queued to the device
- */
-void
-zfcp_scsi_insert_into_fake_queue(struct zfcp_adapter *adapter,
-				 Scsi_Cmnd * new_cmnd)
-{
-	unsigned long flags;
-	Scsi_Cmnd *current_cmnd;
-
-	ZFCP_LOG_DEBUG("Faking SCSI command:\n");
-	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-		      (char *) new_cmnd->cmnd, new_cmnd->cmd_len);
-
-	new_cmnd->host_scribble = NULL;
-
-	write_lock_irqsave(&adapter->fake_list_lock, flags);
-	if (adapter->first_fake_cmnd == NULL) {
-		adapter->first_fake_cmnd = new_cmnd;
-		adapter->fake_scsi_timer.function =
-		    zfcp_scsi_process_and_clear_fake_queue;
-		adapter->fake_scsi_timer.data = (unsigned long) adapter;
-		adapter->fake_scsi_timer.expires =
-		    jiffies + ZFCP_FAKE_SCSI_COMPLETION_TIME;
-		add_timer(&adapter->fake_scsi_timer);
-	} else {
-		for (current_cmnd = adapter->first_fake_cmnd;
-		     current_cmnd->host_scribble != NULL;
-		     current_cmnd =
-		     (Scsi_Cmnd *) (current_cmnd->host_scribble)) ;
-		current_cmnd->host_scribble = (char *) new_cmnd;
-	}
-	write_unlock_irqrestore(&adapter->fake_list_lock, flags);
-}
-
-/*
- * function:    zfcp_scsi_process_and_clear_fake_queue
- *
- * purpose:
- *		
- *
- * returns:
- */
-void
-zfcp_scsi_process_and_clear_fake_queue(unsigned long data)
-{
-	unsigned long flags;
-	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-	Scsi_Cmnd *cur = adapter->first_fake_cmnd;
-	Scsi_Cmnd *next;
-
-	/*
-	 * We need a common lock for scsi_req on command completion
-	 * as well as on command abort to avoid race conditions
-	 * during completions and aborts taking place at the same time.
-	 * It needs to be the outer lock as in the eh_abort_handler.
-	 */
-	read_lock_irqsave(&adapter->abort_lock, flags);
-	write_lock(&adapter->fake_list_lock);
-	while (cur) {
-		next = (Scsi_Cmnd *) cur->host_scribble;
-		cur->host_scribble = NULL;
-		zfcp_cmd_dbf_event_scsi("clrfake", cur);
-		cur->scsi_done(cur);
-		cur = next;
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 2, "fk_done:");
-		debug_event(adapter->req_dbf, 2, &cur, sizeof (unsigned long));
-#endif
-	}
-	adapter->first_fake_cmnd = NULL;
-	write_unlock(&adapter->fake_list_lock);
-	read_unlock_irqrestore(&adapter->abort_lock, flags);
-	return;
-}
-
 void
 zfcp_scsi_block_requests(struct Scsi_Host *shpnt)
 {
@@ -383,25 +290,6 @@ zfcp_scsi_slave_configure(struct scsi_de
 	return 0;
 }
 
-/* Sends command on a round-trip using SCSI stack */
-static void
-zfcp_scsi_queuecommand_fake(Scsi_Cmnd * scpnt, struct zfcp_adapter *adapter)
-{
-	ZFCP_LOG_DEBUG("Looping SCSI IO on the adapter %s.\n",
-		       zfcp_get_busid_by_adapter(adapter));
-	/* 
-	 * Reset everything for devices with retries, allow at least one retry
-	 * for others, e.g. tape.
-	 */
-	scpnt->retries = 0;
-	if (scpnt->allowed == 1) {
-		scpnt->allowed = 2;
-	}
-	set_host_byte(&scpnt->result, DID_SOFT_ERROR);
-	set_driver_byte(&scpnt->result, SUGGEST_RETRY);
-	zfcp_scsi_insert_into_fake_queue(adapter, scpnt);
-}
-
 /* Complete a command immediately handing back DID_ERROR */
 static void
 zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
@@ -460,10 +348,12 @@ zfcp_scsi_queuecommand_stop(Scsi_Cmnd * 
 int
 zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
 {
+	int retval;
 	int temp_ret;
 	struct zfcp_unit *unit;
 	struct zfcp_adapter *adapter;
 
+	retval = 0;
 	/* reset the status for this request */
 	scpnt->result = 0;
 	/* save address of mid layer call back function */
@@ -475,47 +365,38 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt
 	 */
 	adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
 	/* NULL when the adapter was removed from the zfcp list */
-	if (adapter == NULL) {
+	if (unlikely(adapter == NULL)) {
 		zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL);
 		goto out;
 	}
 
-	/* set when we have a unit/port list modification */
-	if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK,
-			     &adapter->status)) {
-		zfcp_scsi_queuecommand_fake(scpnt, adapter);
-		goto out;
-	}
-
 	unit = zfcp_scsi_determine_unit(adapter, scpnt);
-	if (unit == NULL)
+	if (unlikely(unit == NULL))
 		goto out;
 
-	if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)
-	    || !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status)) {
+	if (unlikely(
+	      atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) ||
+	     !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) {
 		zfcp_scsi_queuecommand_stop(scpnt, adapter, unit);
 		goto out;
 	}
-	if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) {
+	if (unlikely(
+	     !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
 		ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx "
 			       "on the port with WWPN 0x%Lx in recovery.\n",
 			       zfcp_get_busid_by_adapter(adapter),
 			       unit->fcp_lun, unit->port->wwpn);
-		zfcp_scsi_queuecommand_fake(scpnt, adapter);
+		retval = SCSI_MLQUEUE_DEVICE_BUSY;
 		goto out;
 	}
 
-	atomic_inc(&adapter->scsi_reqs_active);
-
 	temp_ret = zfcp_fsf_send_fcp_command_task(adapter,
 						  unit,
 						  scpnt, ZFCP_REQ_AUTO_CLEANUP);
 
-	if (temp_ret < 0) {
+	if (unlikely(temp_ret < 0)) {
 		ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n");
-		atomic_dec(&adapter->scsi_reqs_active);
-		wake_up(&adapter->scsi_reqs_active_wq);
-		zfcp_scsi_queuecommand_fake(scpnt, adapter);
+		retval = SCSI_MLQUEUE_HOST_BUSY;
 	} else {
 #ifdef ZFCP_DEBUG_REQUESTS
 		debug_text_event(adapter->req_dbf, 3, "q_scpnt");
@@ -524,7 +405,7 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt
 #endif				/* ZFCP_DEBUG_REQUESTS */
 	}
  out:
-	return 0;
+	return retval;
 }
 
 /*
@@ -557,45 +438,6 @@ zfcp_unit_lookup(struct zfcp_adapter *ad
 }
 
 /*
- * function:    zfcp_scsi_potential_abort_on_fake
- *
- * purpose:
- *
- * returns:     0 - no fake request aborted
- *              1 - fake request was aborted
- *
- * context:	both the adapter->abort_lock and the 
- *              adapter->fake_list_lock are assumed to be held write lock
- *              irqsave
- */
-int
-zfcp_scsi_potential_abort_on_fake(struct zfcp_adapter *adapter,
-				  Scsi_Cmnd * cmnd)
-{
-	Scsi_Cmnd *cur = adapter->first_fake_cmnd;
-	Scsi_Cmnd *pre = NULL;
-	int retval = 0;
-
-	while (cur) {
-		if (cur == cmnd) {
-			if (pre)
-				pre->host_scribble = cur->host_scribble;
-			else
-				adapter->first_fake_cmnd =
-				    (Scsi_Cmnd *) cur->host_scribble;
-			cur->host_scribble = NULL;
-			if (!adapter->first_fake_cmnd)
-				del_timer(&adapter->fake_scsi_timer);
-			retval = 1;
-			break;
-		}
-		pre = cur;
-		cur = (Scsi_Cmnd *) cur->host_scribble;
-	}
-	return retval;
-}
-
-/*
  * function:	zfcp_scsi_eh_abort_handler
  *
  * purpose:	tries to abort the specified (timed out) SCSI command
@@ -663,34 +505,12 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * s
 	 * Race condition between normal (late) completion and abort has
 	 * to be avoided.
 	 * The entirity of all accesses to scsi_req have to be atomic.
-	 * scsi_req is usually part of the fsf_req (for requests which
-	 * are not faked) and thus we block the release of fsf_req
-	 * as long as we need to access scsi_req.
-	 * For faked commands we use the same lock even if they are not
-	 * put into the fsf_req queue. This makes implementation
-	 * easier. 
+	 * scsi_req is usually part of the fsf_req and thus we block the
+	 * release of fsf_req as long as we need to access scsi_req.
 	 */
 	write_lock_irqsave(&adapter->abort_lock, flags);
 
 	/*
-	 * Check if we deal with a faked command, which we may just forget
-	 * about from now on
-	 */
-	write_lock(&adapter->fake_list_lock);
-	/* only need to go through list if there are faked requests */
-	if (adapter->first_fake_cmnd != NULL) {
-		if (zfcp_scsi_potential_abort_on_fake(adapter, scpnt)) {
-			write_unlock(&adapter->fake_list_lock);
-			write_unlock_irqrestore(&adapter->abort_lock, flags);
-			ZFCP_LOG_INFO("A faked command was aborted\n");
-			retval = SUCCESS;
-			strncpy(dbf_result, "##faked", ZFCP_ABORT_DBF_LENGTH);
-			goto out;
-		}
-	}
-	write_unlock(&adapter->fake_list_lock);
-
-	/*
 	 * Check whether command has just completed and can not be aborted.
 	 * Even if the command has just been completed late, we can access
 	 * scpnt since the SCSI stack does not release it at least until
@@ -845,11 +665,6 @@ zfcp_scsi_eh_device_reset_handler(Scsi_C
 
 	spin_unlock_irq(scsi_host->host_lock);
 
-	/*
-	 * We should not be called to reset a target which we 'sent' faked SCSI
-	 * commands since the abort of faked SCSI commands should always
-	 * succeed (simply delete timer). 
-	 */
 	if (!unit) {
 		ZFCP_LOG_NORMAL("bug: Tried to reset a non existant unit.\n");
 		retval = SUCCESS;
@@ -1023,7 +838,6 @@ zfcp_adapter_scsi_register(struct zfcp_a
 		retval = -EIO;
 		goto out;
 	}
-	atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
 	ZFCP_LOG_DEBUG("host registered, scsi_host at 0x%lx\n",
 		       (unsigned long) adapter->scsi_host);
 
@@ -1039,7 +853,12 @@ zfcp_adapter_scsi_register(struct zfcp_a
 	 */
 	adapter->scsi_host->hostdata[0] = (unsigned long) adapter;
 
-	scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev);
+	if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) {
+		scsi_host_put(adapter->scsi_host);
+		retval = -EIO;
+		goto out;
+	}
+	atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
  out:
 	return retval;
 }
@@ -1061,8 +880,9 @@ zfcp_adapter_scsi_unregister(struct zfcp
 		return;
 	scsi_remove_host(shost);
 	scsi_host_put(shost);
-
 	adapter->scsi_host = NULL;
+	atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
+
 	return;
 }
 
diff -puN drivers/s390/scsi/zfcp_sysfs_adapter.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_adapter.c
--- 25/drivers/s390/scsi/zfcp_sysfs_adapter.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_adapter.c	Thu Jan  8 14:11:34 2004
@@ -25,7 +25,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.21 $"
+#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.26 $"
 
 #include <asm/ccwdev.h>
 #include "zfcp_ext.h"
@@ -155,11 +155,8 @@ zfcp_sysfs_port_add_store(struct device 
 
 	retval = 0;
 
-	zfcp_adapter_get(adapter);
-
-	/* try to open port only if adapter is online */
-	if (adapter->ccw_device->online == 1)
-		zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
+	zfcp_erp_port_reopen(port, 0);
+	zfcp_erp_wait(port->adapter);
 	zfcp_port_put(port);
  out:
 	up(&zfcp_data.config_sema);
@@ -219,6 +216,8 @@ zfcp_sysfs_port_remove_store(struct devi
 	zfcp_erp_port_shutdown(port, 0);
 	zfcp_erp_wait(adapter);
 	zfcp_port_put(port);
+	zfcp_sysfs_port_remove_files(&port->sysfs_device,
+				     atomic_read(&port->status));
 	device_unregister(&port->sysfs_device);
  out:
 	up(&zfcp_data.config_sema);
@@ -268,6 +267,7 @@ zfcp_sysfs_adapter_failed_store(struct d
 	zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
 				       ZFCP_SET);
 	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
+	zfcp_erp_wait(adapter);
  out:
 	up(&zfcp_data.config_sema);
 	return retval ? retval : count;
diff -puN drivers/s390/scsi/zfcp_sysfs_port.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_port.c
--- 25/drivers/s390/scsi/zfcp_sysfs_port.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_port.c	Thu Jan  8 14:11:34 2004
@@ -25,7 +25,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.26 $"
+#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.32 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -110,11 +110,9 @@ zfcp_sysfs_unit_add_store(struct device 
 
 	retval = 0;
 
-	zfcp_port_get(port);
-
-	/* try to open unit only if adapter is online */
-	if (port->adapter->ccw_device->online == 1)
-		zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
+	zfcp_erp_unit_reopen(unit, 0);
+	zfcp_erp_wait(unit->port->adapter);
+	wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0);
 	zfcp_unit_put(unit);
  out:
 	up(&zfcp_data.config_sema);
@@ -170,6 +168,7 @@ zfcp_sysfs_unit_remove_store(struct devi
 	zfcp_erp_unit_shutdown(unit, 0);
 	zfcp_erp_wait(unit->port->adapter);
 	zfcp_unit_put(unit);
+	zfcp_sysfs_unit_remove_files(&unit->sysfs_device);
 	device_unregister(&unit->sysfs_device);
  out:
 	up(&zfcp_data.config_sema);
@@ -217,6 +216,7 @@ zfcp_sysfs_port_failed_store(struct devi
 	}
 	zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
+	zfcp_erp_wait(port->adapter);
  out:
 	up(&zfcp_data.config_sema);
 	return retval ? retval : count;
@@ -293,7 +293,7 @@ static struct attribute_group zfcp_port_
 };
 
 /**
- * zfcp_sysfs_create_port_files - create sysfs port files
+ * zfcp_sysfs_port_create_files - create sysfs port files
  * @dev: pointer to belonging device
  *
  * Create all attributes of the sysfs representation of a port.
@@ -315,5 +315,19 @@ zfcp_sysfs_port_create_files(struct devi
 	return retval;
 }
 
+/**
+ * zfcp_sysfs_port_remove_files - remove sysfs port files
+ * @dev: pointer to belonging device
+ *
+ * Remove all attributes of the sysfs representation of a port.
+ */
+void
+zfcp_sysfs_port_remove_files(struct device *dev, u32 flags)
+{
+	sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group);
+	if (!(flags & ZFCP_STATUS_PORT_NAMESERVER))
+		sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group);
+}
+
 #undef ZFCP_LOG_AREA
 #undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_sysfs_unit.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_unit.c
--- 25/drivers/s390/scsi/zfcp_sysfs_unit.c~s390-07-zfcp-host-adapter	Thu Jan  8 14:11:34 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_unit.c	Thu Jan  8 14:11:34 2004
@@ -25,7 +25,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.17 $"
+#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.19 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -186,5 +186,17 @@ zfcp_sysfs_unit_create_files(struct devi
 	return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group);
 }
 
+/** 
+ * zfcp_sysfs_remove_unit_files - remove sysfs unit files
+ * @dev: pointer to belonging device
+ *
+ * Remove all attributes of the sysfs representation of a unit.
+ */
+void
+zfcp_sysfs_unit_remove_files(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group);
+}
+
 #undef ZFCP_LOG_AREA
 #undef ZFCP_LOG_AREA_PREFIX

_