Add new features to the zfcp host adapater driver:
  - Add support for HBA API (FC-HBA).
  - Add support for FCP access control.
  - Error recovery enhancements.

 Documentation/ioctl-number.txt         |    2 
 drivers/s390/scsi/zfcp_ext.h           |   51 
 drivers/s390/scsi/zfcp_sysfs_adapter.c |   21 
 drivers/s390/scsi/zfcp_sysfs_driver.c  |   19 
 drivers/s390/scsi/zfcp_sysfs_port.c    |   20 
 drivers/s390/scsi/zfcp_sysfs_unit.c    |   13 



---

 25-akpm/Documentation/ioctl-number.txt         |    2 
 25-akpm/drivers/s390/scsi/zfcp_aux.c           |  898 +++++++---
 25-akpm/drivers/s390/scsi/zfcp_ccw.c           |   72 
 25-akpm/drivers/s390/scsi/zfcp_def.h           |  559 +++++-
 25-akpm/drivers/s390/scsi/zfcp_erp.c           |  538 +++++-
 25-akpm/drivers/s390/scsi/zfcp_ext.h           |   51 
 25-akpm/drivers/s390/scsi/zfcp_fsf.c           | 2048 +++++++++++++++++--------
 25-akpm/drivers/s390/scsi/zfcp_fsf.h           |  158 +
 25-akpm/drivers/s390/scsi/zfcp_qdio.c          |  367 ++++
 25-akpm/drivers/s390/scsi/zfcp_scsi.c          |  603 +------
 25-akpm/drivers/s390/scsi/zfcp_sysfs_adapter.c |   21 
 25-akpm/drivers/s390/scsi/zfcp_sysfs_driver.c  |   19 
 25-akpm/drivers/s390/scsi/zfcp_sysfs_port.c    |   20 
 25-akpm/drivers/s390/scsi/zfcp_sysfs_unit.c    |   13 
 14 files changed, 3746 insertions(+), 1623 deletions(-)

diff -puN Documentation/ioctl-number.txt~s390-zfcp-host-adapter Documentation/ioctl-number.txt
--- 25/Documentation/ioctl-number.txt~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/Documentation/ioctl-number.txt	Fri Feb 20 16:00:58 2004
@@ -187,3 +187,5 @@ Code	Seq#	Include File		Comments
 0xB1	00-1F	PPPoX			<mailto:mostrows@styx.uwaterloo.ca>
 0xCB	00-1F	CBM serial IEC bus	in development:
 					<mailto:michael.klein@puffin.lb.shuttle.de>
+0xDD	00-3F	ZFCP device driver	see drivers/s390/scsi/
+					<mailto:aherrman@de.ibm.com>
diff -puN drivers/s390/scsi/zfcp_aux.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_aux.c
--- 25/drivers/s390/scsi/zfcp_aux.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_aux.c	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  *
  * FCP adapter driver for IBM eServer zSeries
  *
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com>
- *            Aron Zeh <arzeh@de.ibm.com>
- *            Wolfgang Taphorn <taphorn@de.ibm.com>
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com>
  *            Heiko Carstens <heiko.carstens@de.ibm.com>
  *
@@ -28,7 +29,7 @@
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_AUX_REVISION "$Revision: 1.79 $"
+#define ZFCP_AUX_REVISION "$Revision: 1.98 $"
 
 /********************** INCLUDES *********************************************/
 
@@ -61,6 +62,9 @@
 #include <asm/cpcmd.h>		/* Debugging only */
 #include <asm/processor.h>	/* Debugging only */
 
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+
 /* accumulated log level (module parameter) */
 static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;
 static char *device;
@@ -73,7 +77,7 @@ static void __exit zfcp_module_exit(void
 int zfcp_reboot_handler(struct notifier_block *, unsigned long, void *);
 
 /* FCP related */
-static void zfcp_nameserver_request_handler(struct zfcp_fsf_req *);
+static void zfcp_ns_gid_pn_handler(unsigned long);
 
 /* miscellaneous */
 #ifdef ZFCP_STAT_REQSIZES
@@ -83,6 +87,34 @@ static int zfcp_statistics_clear(struct 
 static int zfcp_statistics_new(struct list_head *, u32);
 #endif
 
+static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static inline int zfcp_sg_list_free(struct zfcp_sg_list *);
+static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, void *,
+					      size_t);
+static inline int zfcp_sg_list_copy_to_user(void *, struct zfcp_sg_list *,
+					    size_t);
+
+static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *,
+	unsigned int, unsigned long);
+
+#define ZFCP_CFDC_IOC_MAGIC                     0xDD
+#define ZFCP_CFDC_IOC \
+	_IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)
+
+#ifdef CONFIG_S390_SUPPORT
+static struct ioctl_trans zfcp_ioctl_trans = {ZFCP_CFDC_IOC, (void*) sys_ioctl};
+#endif
+
+static struct file_operations zfcp_cfdc_fops = {
+	.ioctl = zfcp_cfdc_dev_ioctl
+};
+
+static struct miscdevice zfcp_cfdc_misc = {
+	.minor = ZFCP_CFDC_DEV_MINOR,
+	.name = ZFCP_CFDC_DEV_NAME,
+	.fops = &zfcp_cfdc_fops
+};
+
 /*********************** KERNEL/MODULE PARAMETERS  ***************************/
 
 /* declare driver module init/cleanup functions */
@@ -128,7 +160,7 @@ _zfcp_hex_dump(char *addr, int count)
 		if ((i % 32) == 31)
 			printk("\n");
 	}
-	if ((i % 32) != 31)
+	if (((i-1) % 32) != 31)
 		printk("\n");
 }
 
@@ -137,7 +169,6 @@ _zfcp_hex_dump(char *addr, int count)
 /****************************************************************/
 
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_OTHER
-#define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_OTHER
 
 #ifdef ZFCP_STAT_REQSIZES
 
@@ -242,7 +273,7 @@ zfcp_cmd_dbf_event_fsf(const char *text,
 {
 #ifdef ZFCP_DEBUG_COMMANDS
 	struct zfcp_adapter *adapter = fsf_req->adapter;
-	Scsi_Cmnd *scsi_cmnd;
+	struct scsi_cmnd *scsi_cmnd;
 	int level = 3;
 	int i;
 	unsigned long flags;
@@ -258,6 +289,8 @@ zfcp_cmd_dbf_event_fsf(const char *text,
 			    sizeof (u32));
 		debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
 			    sizeof (unsigned long));
+		debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
+			    min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
 		for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH)
 			debug_event(adapter->cmd_dbf,
 				    level,
@@ -268,8 +301,10 @@ zfcp_cmd_dbf_event_fsf(const char *text,
 #endif
 }
 
+/* XXX additionally log unit if available */
+/* ---> introduce new parameter for unit, see 2.4 code */
 void
-zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd)
+zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
 {
 #ifdef ZFCP_DEBUG_COMMANDS
 	struct zfcp_adapter *adapter;
@@ -287,6 +322,8 @@ 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));
+	debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
+		    min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
 	if (likely(fsf_req)) {
 		debug_event(adapter->cmd_dbf, level, &fsf_req,
 			    sizeof (unsigned long));
@@ -359,13 +396,12 @@ 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);
+	read_lock_irq(&zfcp_data.config_lock);
 	list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
 		if (strcmp(zfcp_data.init_busid,
 			   zfcp_get_busid_by_adapter(adapter)) == 0) {
@@ -373,7 +409,7 @@ zfcp_init_device_configure(void)
 			found = 1;
 			break;
 		}
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	read_unlock_irq(&zfcp_data.config_lock);
 	if (!found)
 		goto out_adapter;
 	port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0);
@@ -419,6 +455,28 @@ zfcp_module_init(void)
 	zfcp_statistics_init_all();
 #endif
 
+#ifdef CONFIG_S390_SUPPORT
+	retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd,
+					     zfcp_ioctl_trans.handler);
+	if (retval != 0) {
+		ZFCP_LOG_INFO("Cannot register a 32-bit support of "
+			      "the IOC handler\n");
+		goto out_ioctl32;
+	}
+#endif
+	retval = misc_register(&zfcp_cfdc_misc);
+	if (retval != 0) {
+		ZFCP_LOG_INFO(
+			"Device file for the control file data channel "
+			"cannot be registered\n");
+		goto out_misc_register;
+	} else {
+		ZFCP_LOG_INFO(
+			"Device file for the control file data channel "
+			"has become MAJOR/MINOR numbers %d/%d\n",
+			ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor);
+	}
+
 	/* Initialise proc semaphores */
 	sema_init(&zfcp_data.config_sema, 1);
 
@@ -445,6 +503,12 @@ zfcp_module_init(void)
 
  out_ccw_register:
 	unregister_reboot_notifier(&zfcp_data.reboot_notifier);
+	misc_deregister(&zfcp_cfdc_misc);
+ out_misc_register:
+#ifdef CONFIG_S390_SUPPORT
+	unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
+ out_ioctl32:
+#endif
 #ifdef ZFCP_STAT_REQSIZES
 	zfcp_statistics_clear_all();
 #endif
@@ -458,6 +522,10 @@ zfcp_module_exit(void)
 {
 	unregister_reboot_notifier(&zfcp_data.reboot_notifier);
 	zfcp_ccw_unregister();
+	misc_deregister(&zfcp_cfdc_misc);
+#ifdef CONFIG_S390_SUPPORT
+	unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
+#endif
 #ifdef ZFCP_STAT_REQSIZES
 	zfcp_statistics_clear_all();
 #endif
@@ -480,15 +548,372 @@ zfcp_reboot_handler(struct notifier_bloc
 	return NOTIFY_DONE;
 }
 
+
+/*
+ * function:    zfcp_cfdc_dev_ioctl
+ *
+ * purpose:     Handle control file upload/download transaction via IOCTL
+ *		interface
+ *
+ * returns:     0           - Operation completed successfuly
+ *              -ENOTTY     - Unknown IOCTL command
+ *              -EINVAL     - Invalid sense data record
+ *              -ENXIO      - The FCP adapter is not available
+ *              -EOPNOTSUPP - The FCP adapter does not have CFDC support
+ *              -ENOMEM     - Insufficient memory
+ *              -EFAULT     - User space memory I/O operation fault
+ *              -EPERM      - Cannot create or queue FSF request or create SBALs
+ */
+static int
+zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
+                    unsigned int command, unsigned long buffer)
+{
+	struct zfcp_cfdc_sense_data sense_data, *sense_data_user;
+	struct zfcp_adapter *adapter = NULL;
+	struct zfcp_fsf_req *fsf_req = NULL;
+	struct zfcp_sg_list *sg_list = NULL;
+	u32 fsf_command, option;
+	char *bus_id = NULL;
+	int retval = 0;
+
+	ZFCP_LOG_NORMAL(
+		"Control file data channel transaction opened\n");
+
+	sg_list = kmalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL);
+	if (sg_list == NULL) {
+		ZFCP_LOG_NORMAL(
+			"Not enough memory for the scatter-gather list\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+	sg_list->count = 0;
+
+	if (command != ZFCP_CFDC_IOC) {
+		ZFCP_LOG_NORMAL(
+			"IOC request code 0x%x is not valid\n",
+			command);
+		retval = -ENOTTY;
+		goto out;
+	}
+
+	if ((sense_data_user = (struct zfcp_cfdc_sense_data*)buffer) == NULL) {
+		ZFCP_LOG_NORMAL(
+			"Sense data record is required\n");
+		retval = -EINVAL;
+		goto out;
+	}
+
+	retval = copy_from_user(&sense_data, sense_data_user,
+		sizeof(struct zfcp_cfdc_sense_data));
+	if (retval) {
+		ZFCP_LOG_NORMAL("Cannot copy sense data record from user space "
+				"memory\n");
+		retval = -EFAULT;
+		goto out;
+	}
+
+	if (sense_data.signature != ZFCP_CFDC_SIGNATURE) {
+		ZFCP_LOG_NORMAL(
+			"No valid sense data request signature 0x%08x found\n",
+			ZFCP_CFDC_SIGNATURE);
+		retval = -EINVAL;
+		goto out;
+	}
+
+	switch (sense_data.command) {
+
+	case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL:
+		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+		option = FSF_CFDC_OPTION_NORMAL_MODE;
+		break;
+
+	case ZFCP_CFDC_CMND_DOWNLOAD_FORCE:
+		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+		option = FSF_CFDC_OPTION_FORCE;
+		break;
+
+	case ZFCP_CFDC_CMND_FULL_ACCESS:
+		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+		option = FSF_CFDC_OPTION_FULL_ACCESS;
+		break;
+
+	case ZFCP_CFDC_CMND_RESTRICTED_ACCESS:
+		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
+		option = FSF_CFDC_OPTION_RESTRICTED_ACCESS;
+		break;
+
+	case ZFCP_CFDC_CMND_UPLOAD:
+		fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE;
+		option = 0;
+		break;
+
+	default:
+		ZFCP_LOG_NORMAL(
+			"Command code 0x%08x is not valid\n",
+			sense_data.command);
+		retval = -EINVAL;
+		goto out;
+	}
+
+	bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+	if (bus_id == NULL) {
+		ZFCP_LOG_NORMAL("Out of memory!\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+	snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x",
+		(sense_data.devno >> 24),
+		(sense_data.devno >> 16) & 0xFF,
+		(sense_data.devno & 0xFFFF));
+
+	retval = -ENXIO;
+	read_lock_irq(&zfcp_data.config_lock);
+	list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) {
+		if (strncmp(bus_id, zfcp_get_busid_by_adapter(adapter),
+		    BUS_ID_SIZE) == 0) {
+			zfcp_adapter_get(adapter);
+			retval = 0;
+			break;
+		}
+	}
+	read_unlock_irq(&zfcp_data.config_lock);
+
+	kfree(bus_id);
+
+	if (retval != 0) {
+		ZFCP_LOG_NORMAL("Specified adapter does not exist\n");
+		goto out;
+	}
+
+	if (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE) {
+		retval = zfcp_sg_list_alloc(sg_list,
+					    ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
+		if (retval) {
+			ZFCP_LOG_NORMAL("Not enough memory for the "
+					"scatter-gather list\n");
+			retval = -ENOMEM;
+			goto out;
+		}
+	}
+
+	if ((sense_data.command & ZFCP_CFDC_DOWNLOAD) &&
+	    (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE)) {
+		retval = zfcp_sg_list_copy_from_user(
+			sg_list, &sense_data_user->control_file,
+			ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
+		if (retval) {
+			ZFCP_LOG_NORMAL("Cannot copy control file from user "
+					"space memory\n");
+			retval = -EFAULT;
+			goto out;
+		}
+	}
+
+	retval = zfcp_fsf_control_file(
+		adapter, &fsf_req, fsf_command, option, sg_list);
+	if (retval == -EOPNOTSUPP) {
+		ZFCP_LOG_NORMAL(
+			"Specified adapter does not support control file\n");
+		goto out;
+	} else if (retval != 0) {
+		ZFCP_LOG_NORMAL(
+			"Cannot create or queue FSF request or create SBALs\n");
+		retval = -EPERM;
+		goto out;
+	}
+
+	wait_event(fsf_req->completion_wq,
+	           fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+	sense_data.fsf_status = fsf_req->qtcb->header.fsf_status;
+	memcpy(&sense_data.fsf_status_qual,
+	       &fsf_req->qtcb->header.fsf_status_qual,
+	       sizeof(union fsf_status_qual));
+	memcpy(&sense_data.payloads, &fsf_req->qtcb->bottom.support.els, 256);
+
+	retval = copy_to_user(sense_data_user, &sense_data,
+		sizeof(struct zfcp_cfdc_sense_data));
+	if (retval) {
+		ZFCP_LOG_NORMAL(
+			"Cannot copy sense data record to user space memory\n");
+		retval = -EFAULT;
+		goto out;
+	}
+
+	if (sense_data.command & ZFCP_CFDC_UPLOAD) {
+		retval = zfcp_sg_list_copy_to_user(
+			&sense_data_user->control_file, sg_list,
+			ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
+		if (retval) {
+			ZFCP_LOG_NORMAL("Cannot copy control file to user "
+					"space memory\n");
+			retval = -EFAULT;
+			goto out;
+		}
+	}
+
+ out:
+	if (fsf_req != NULL)
+		zfcp_fsf_req_cleanup(fsf_req);
+
+	if ((adapter != NULL) && (retval != -ENXIO))
+		zfcp_adapter_put(adapter);
+
+	if (sg_list != NULL) {
+		zfcp_sg_list_free(sg_list);
+		kfree(sg_list);
+	}
+
+	ZFCP_LOG_NORMAL(
+		"Control file data channel transaction closed\n");
+
+	return retval;
+}
+
+
+/*
+ * function:    zfcp_sg_list_alloc
+ *
+ * purpose:     Create a scatter-gather list of the specified size
+ *
+ * returns:     0       - Scatter gather list is created
+ *              -ENOMEM - Insufficient memory (*list_ptr is then set to NULL)
+ */
+static inline int
+zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
+{
+	struct scatterlist *sg;
+	int i;
+	int retval = 0;
+
+	sg_list->count = size >> PAGE_SHIFT;
+	if (size & ~PAGE_MASK)
+		sg_list->count++;
+	sg_list->sg = kmalloc(sg_list->count * sizeof(struct scatterlist),
+			      GFP_KERNEL);
+	if (sg_list->sg == NULL) {
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
+		sg->length = min(size, PAGE_SIZE);
+		sg->offset = 0;
+		sg->page = alloc_pages(GFP_KERNEL, 0);
+		if (sg->page == NULL) {
+			sg_list->count = i;
+			zfcp_sg_list_free(sg_list);
+			retval = -ENOMEM;
+			goto out;
+		}
+		size -= sg->length;
+	}
+
+ out:
+	return retval;
+}
+
+
+/*
+ * function:    zfcp_sg_list_free
+ *
+ * purpose:     Destroy a scatter-gather list and release memory
+ *
+ * returns:     Always 0
+ */
+static inline int
+zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
+{
+	struct scatterlist *sg;
+	int i;
+	int retval = 0;
+
+	BUG_ON((sg_list->sg == NULL) || (sg_list == NULL));
+
+	for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++)
+		__free_pages(sg->page, 0);
+
+	return retval;
+}
+
+
+/*
+ * function:    zfcp_sg_list_copy_from_user
+ *
+ * purpose:     Copy data from user space memory to the scatter-gather list
+ *
+ * returns:     0       - The data has been copied from user
+ *              -EFAULT - Memory I/O operation fault
+ */
+static inline int
+zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer,
+                            size_t size)
+{
+	struct scatterlist *sg;
+	unsigned int length;
+	void *zfcp_buffer;
+	int retval = 0;
+
+	for (sg = sg_list->sg; size > 0; sg++) {
+		length = min((unsigned int)size, sg->length);
+		zfcp_buffer = (void*)
+			((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset);
+		if (copy_from_user(zfcp_buffer, user_buffer, length)) {
+			ZFCP_LOG_INFO("Memory error (copy_from_user)\n");
+			retval = -EFAULT;
+			goto out;
+		}
+		user_buffer += length;
+		size -= length;
+	}
+
+ out:
+	return retval;
+}
+
+
+/*
+ * function:    zfcp_sg_list_copy_to_user
+ *
+ * purpose:     Copy data from the scatter-gather list to user space memory
+ *
+ * returns:     0       - The data has been copied to user
+ *              -EFAULT - Memory I/O operation fault
+ */
+static inline int
+zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list,
+                          size_t size)
+{
+	struct scatterlist *sg;
+	unsigned int length;
+	void *zfcp_buffer;
+	int retval = 0;
+
+	for (sg = sg_list->sg; size > 0; sg++) {
+		length = min((unsigned int)size, sg->length);
+		zfcp_buffer = (void*)
+			((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset);
+		if (copy_to_user(user_buffer, zfcp_buffer, length)) {
+			ZFCP_LOG_INFO("Memory error (copy_to_user)\n");
+			retval = -EFAULT;
+			goto out;
+		}
+		user_buffer += length;
+		size -= length;
+	}
+
+ out:
+	return retval;
+}
+
+
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
 
 /****************************************************************/
 /****** Functions for configuration/set-up of structures ********/
 /****************************************************************/
 
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_CONFIG
 
 /**
  * zfcp_get_unit_by_lun - find unit in unit list of port by fcp lun
@@ -684,83 +1109,92 @@ zfcp_mempool_free(void *element, void *s
 static int
 zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
 {
-	adapter->pool.erp_fsf = mempool_create(
-		1,
-		zfcp_mempool_alloc,
-		zfcp_mempool_free,
-		(void *) ZFCP_QTCB_AND_REQ_SIZE);
-	if (!adapter->pool.erp_fsf) {
-		ZFCP_LOG_INFO
-		    ("error: FCP command buffer pool allocation failed\n");
+	adapter->pool.fsf_req_erp =
+		mempool_create(ZFCP_POOL_FSF_REQ_ERP_NR,
+			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+			       sizeof(struct zfcp_fsf_req_pool_element));
+
+	if (NULL == adapter->pool.fsf_req_erp) {
+		ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_erp)\n");
 		return -ENOMEM;
 	}
 
-	adapter->pool.nameserver = mempool_create(
-		1,
-		zfcp_mempool_alloc,
-		zfcp_mempool_free,
-		(void *) (2 *  sizeof (struct fc_ct_iu)));
-	if (!adapter->pool.nameserver) {
-		ZFCP_LOG_INFO
-		    ("error: Nameserver buffer pool allocation failed\n");
+	adapter->pool.fsf_req_scsi =
+		mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR,
+			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+			       sizeof(struct zfcp_fsf_req_pool_element));
+
+	if (NULL == adapter->pool.fsf_req_scsi) {
+		ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_scsi)\n");
 		return -ENOMEM;
 	}
 
-	adapter->pool.status_read_fsf = mempool_create(
-		ZFCP_STATUS_READS_RECOM,
-		zfcp_mempool_alloc,
-		zfcp_mempool_free,
-		(void *) sizeof (struct zfcp_fsf_req));
-	if (!adapter->pool.status_read_fsf) {
-		ZFCP_LOG_INFO
-		    ("error: Status read request pool allocation failed\n");
+	adapter->pool.fsf_req_abort =
+		mempool_create(ZFCP_POOL_FSF_REQ_ABORT_NR,
+			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+			       sizeof(struct zfcp_fsf_req_pool_element));
+
+	if (NULL == adapter->pool.fsf_req_abort) {
+		ZFCP_LOG_INFO("error: pool allocation failed "
+			      "(fsf_req_abort)\n");
 		return -ENOMEM;
 	}
 
-	adapter->pool.status_read_buf = mempool_create(
-		ZFCP_STATUS_READS_RECOM,
-		zfcp_mempool_alloc,
-		zfcp_mempool_free,
-		(void *) sizeof (struct	fsf_status_read_buffer));
-	if (!adapter->pool.status_read_buf) {
-		ZFCP_LOG_INFO
-		    ("error: Status read buffer pool allocation failed\n");
+	adapter->pool.fsf_req_status_read =
+		mempool_create(ZFCP_POOL_STATUS_READ_NR,
+			       zfcp_mempool_alloc, zfcp_mempool_free,
+			       (void *) sizeof(struct zfcp_fsf_req));
+
+	if (NULL == adapter->pool.fsf_req_status_read) {
+		ZFCP_LOG_INFO("error: pool allocation failed "
+			      "(fsf_req_status_read\n");
 		return -ENOMEM;
 	}
 
-	adapter->pool.fcp_command_fsf = mempool_create(
-		1,
-		zfcp_mempool_alloc,
-		zfcp_mempool_free,
-		(void *)
-		ZFCP_QTCB_AND_REQ_SIZE);
-	if (!adapter->pool.fcp_command_fsf) {
-		ZFCP_LOG_INFO
-		    ("error: FCP command buffer pool allocation failed\n");
+	adapter->pool.data_status_read =
+		mempool_create(ZFCP_POOL_STATUS_READ_NR,
+			       zfcp_mempool_alloc, zfcp_mempool_free,
+			       (void *) sizeof(struct fsf_status_read_buffer));
+
+	if (NULL == adapter->pool.data_status_read) {
+		ZFCP_LOG_INFO("error: pool allocation failed "
+			      "(data_status_read)\n");
+		return -ENOMEM;
+	}
+
+	adapter->pool.data_gid_pn =
+		mempool_create(ZFCP_POOL_DATA_GID_PN_NR,
+			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
+			       sizeof(struct zfcp_gid_pn_data));
+
+	if (NULL == adapter->pool.data_gid_pn) {
+		ZFCP_LOG_INFO("error: pool allocation failed (data_gid_pn)\n");
 		return -ENOMEM;
 	}
-	init_timer(&adapter->pool.fcp_command_fsf_timer);
-	adapter->pool.fcp_command_fsf_timer.function =
-	    zfcp_erp_scsi_low_mem_buffer_timeout_handler;
-	adapter->pool.fcp_command_fsf_timer.data = (unsigned long) adapter;
 
 	return 0;
 }
 
-/* locks:       must only be called with zfcp_data.config_sema taken */
+/**
+ * zfcp_free_low_mem_buffers - free memory pools of an adapter
+ * @adapter: pointer to zfcp_adapter for which memory pools should be freed
+ * locking:  zfcp_data.config_sema must be held
+ */
 static void
 zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
 {
-	if (adapter->pool.status_read_fsf)
-		mempool_destroy(adapter->pool.status_read_fsf);
-	if (adapter->pool.status_read_buf)
-		mempool_destroy(adapter->pool.status_read_buf);
-	if (adapter->pool.nameserver)
-		mempool_destroy(adapter->pool.nameserver);
-	if (adapter->pool.erp_fsf)
-		mempool_destroy(adapter->pool.erp_fsf);
-	if (adapter->pool.fcp_command_fsf)
-		mempool_destroy(adapter->pool.fcp_command_fsf);
+	if (adapter->pool.fsf_req_erp)
+		mempool_destroy(adapter->pool.fsf_req_erp);
+	if (adapter->pool.fsf_req_scsi)
+		mempool_destroy(adapter->pool.fsf_req_scsi);
+	if (adapter->pool.fsf_req_abort)
+		mempool_destroy(adapter->pool.fsf_req_abort);
+	if (adapter->pool.fsf_req_status_read)
+		mempool_destroy(adapter->pool.fsf_req_status_read);
+	if (adapter->pool.data_status_read)
+		mempool_destroy(adapter->pool.data_status_read);
+	if (adapter->pool.data_gid_pn)
+		mempool_destroy(adapter->pool.data_gid_pn);
 }
 
 /*
@@ -859,7 +1293,7 @@ zfcp_adapter_enqueue(struct ccw_device *
 
 #ifdef ZFCP_DEBUG_REQUESTS
 	/* debug feature area which records fsf request sequence numbers */
-	sprintf(dbf_name, ZFCP_REQ_DBF_NAME "0x%s",
+	sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s",
 		zfcp_get_busid_by_adapter(adapter));
 	adapter->req_dbf = debug_register(dbf_name,
 					  ZFCP_REQ_DBF_INDEX,
@@ -954,15 +1388,6 @@ zfcp_adapter_enqueue(struct ccw_device *
 	debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
 	debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
 
-	retval = zfcp_erp_thread_setup(adapter);
-	if (retval) {
-		ZFCP_LOG_INFO("error: out of resources. "
-			      "error recovery thread for the adapter %s "
-			      "could not be started\n",
-			      zfcp_get_busid_by_adapter(adapter));
-		goto thread_failed;
-	}
-
 	/* put allocated adapter at list tail */
 	write_lock_irq(&zfcp_data.config_lock);
 	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
@@ -973,15 +1398,6 @@ zfcp_adapter_enqueue(struct ccw_device *
 
 	goto out;
 
- thread_failed:
-	if (qdio_free(adapter->ccw_device) != 0)
-		ZFCP_LOG_NORMAL
-		    ("bug: could not free memory used by data transfer "
-		     "mechanism for adapter %s\n",
-		     zfcp_get_busid_by_adapter(adapter));
-
-	debug_unregister(adapter->erp_dbf);
-
  failed_erp_dbf:
 #ifdef ZFCP_DEBUG_INCOMING_ELS
 	debug_unregister(adapter->in_els_dbf);
@@ -1007,7 +1423,11 @@ zfcp_adapter_enqueue(struct ccw_device *
 	dev_set_drvdata(&ccw_device->dev, NULL);
  failed_low_mem_buffers:
 	zfcp_free_low_mem_buffers(adapter);
-	qdio_free(ccw_device);
+	if (qdio_free(ccw_device) != 0)
+		ZFCP_LOG_NORMAL
+		    ("bug: could not free memory used by data transfer "
+		     "mechanism for adapter %s\n",
+		     zfcp_get_busid_by_adapter(adapter));
  qdio_allocate_failed:
 	zfcp_qdio_free_queues(adapter);
  queues_alloc_failed:
@@ -1060,9 +1480,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter
 		       "%i adapters still in list\n",
 		       (unsigned long) adapter, zfcp_data.adapters);
 
-	retval = zfcp_erp_thread_kill(adapter);
-
-	retval |= qdio_free(adapter->ccw_device);
+	retval = qdio_free(adapter->ccw_device);
 	if (retval)
 		ZFCP_LOG_NORMAL
 		    ("bug: could not free memory used by data transfer "
@@ -1261,14 +1679,12 @@ zfcp_nameserver_enqueue(struct zfcp_adap
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
 
 /****************************************************************/
 /******* Fibre Channel Standard related Functions  **************/
 /****************************************************************/
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_FC
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_FC
 
 void
 zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
@@ -1361,7 +1777,7 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a
 				     "0x%Lx.\n", port->wwpn);
 				debug_text_event(adapter->erp_dbf, 1,
 						 "unsol_els_rscnk:");
-				zfcp_erp_port_reopen(port, 0);
+				zfcp_test_link(port);
 			}
 		}
 		read_unlock_irqrestore(&zfcp_data.config_lock, flags);
@@ -1462,222 +1878,180 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_re
 		zfcp_fsf_incoming_els_rscn(adapter, status_buffer);
 	else
 		zfcp_fsf_incoming_els_unknown(adapter, status_buffer);
-}
-
-/*
- * function:	zfcp_release_nameserver_buffers
- *
- * purpose:	
- *
- * returns:
- */
-static void
-zfcp_release_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
-{
-	struct zfcp_adapter *adapter = fsf_req->adapter;
-	void *buffer = fsf_req->data.send_generic.outbuf;
 
-	/* FIXME: not sure about appeal of this new flag (martin) */
-	if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOLBUF)
-		mempool_free(buffer, adapter->pool.nameserver);
-	else
-		kfree(buffer);
 }
 
-/*
- * function:	zfcp_get_nameserver_buffers
- *
- * purpose:	
- *
- * returns:
- *
- * locks:       fsf_request_list_lock is held when doing buffer pool 
- *              operations
+
+/**
+ * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request
+ * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data
+ * @pool: pointer to mempool_t if non-null memory pool is used for allocation
  */
 static int
-zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
+zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
 {
-	struct zfcp_send_generic *data = &fsf_req->data.send_generic;
-	struct zfcp_adapter *adapter = fsf_req->adapter;
-	int retval = 0;
+	struct zfcp_gid_pn_data *data;
 
-	data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC);
-	if (data->outbuf) {
-		memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
+	if (pool != NULL) {
+		data = mempool_alloc(pool, GFP_ATOMIC);
+		if (likely(data != NULL)) {
+			data->ct.pool = pool;
+		}
 	} else {
-		ZFCP_LOG_DEBUG("Out of memory. Could not allocate at "
-			       "least one of the buffers "
-			       "required for a name-server request on the"
-			       "adapter %s directly.. trying emergency pool\n",
-			       zfcp_get_busid_by_adapter(adapter));
-		data->outbuf =
-		    mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC);
-		if (!data->outbuf) {
-			ZFCP_LOG_DEBUG
-				("Out of memory. Could not get emergency "
-				 "buffer required for a name-server request "
-				 "on the adapter %s. All buffers are in "
-				 "use.\n",
-				 zfcp_get_busid_by_adapter(adapter));
-			retval = -ENOMEM;
-			goto out;
+		data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC);
 		}
-		memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
-		fsf_req->status |= ZFCP_STATUS_FSFREQ_POOLBUF;
+
+        if (NULL == data){
+		ZFCP_LOG_DEBUG("Out of memory.\n");
+                return -ENOMEM;
 	}
-	data->outbuf_length = sizeof (struct fc_ct_iu);
-	data->inbuf_length = sizeof (struct fc_ct_iu);
-	data->inbuf =
-	    (char *) ((unsigned long) data->outbuf + sizeof (struct fc_ct_iu));
- out:
-	return retval;
+
+	memset(data, 0, sizeof(*data));
+        data->ct.req = &data->req;
+        data->ct.resp = &data->resp;
+	data->ct.req_count = data->ct.resp_count = 1;
+	zfcp_address_to_sg(&data->ct_iu_req, &data->req);
+        zfcp_address_to_sg(&data->ct_iu_resp, &data->resp);
+        data->req.length = sizeof(struct ct_iu_gid_pn_req);
+        data->resp.length = sizeof(struct ct_iu_gid_pn_resp);
+
+	*gid_pn = data;
+	return 0;
 }
 
-/*
- * function:	zfcp_nameserver_request
- *
- * purpose:	
- *
- * returns:
+/**
+ * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request
+ * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed
  */
-int
-zfcp_nameserver_request(struct zfcp_erp_action *erp_action)
+static void
+zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
 {
-	int retval = 0;
-	struct fc_ct_iu *fc_ct_iu;
-	unsigned long lock_flags;
-
-	/* setup new FSF request */
-	retval = zfcp_fsf_req_create(erp_action->adapter,
-				     FSF_QTCB_SEND_GENERIC,
-				     &lock_flags,
-				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
-				     &(erp_action->fsf_req));
-	if (retval < 0) {
-		ZFCP_LOG_INFO("error: Out of resources. Could not create a "
-			      "nameserver registration request for "
-			      "adapter %s.\n",
-			      zfcp_get_busid_by_adapter(erp_action->adapter));
-		goto failed_req;
-	}
-	retval = zfcp_get_nameserver_buffers(erp_action->fsf_req);
-	if (retval < 0) {
-		ZFCP_LOG_INFO("error: Out of memory. Could not allocate one of "
-			      "the buffers required for a nameserver request "
-			      "on adapter %s.\n",
-			      zfcp_get_busid_by_adapter(erp_action->adapter));
-		goto failed_buffers;
-	}
-
-	/* setup name-server request in first page */
-	fc_ct_iu =
-	    (struct fc_ct_iu *) erp_action->fsf_req->data.send_generic.outbuf;
-	fc_ct_iu->revision = ZFCP_CT_REVISION;
-	fc_ct_iu->gs_type = ZFCP_CT_DIRECTORY_SERVICE;
-	fc_ct_iu->gs_subtype = ZFCP_CT_NAME_SERVER;
-	fc_ct_iu->options = ZFCP_CT_SYNCHRONOUS;
-	fc_ct_iu->cmd_rsp_code = ZFCP_CT_GID_PN;
-	fc_ct_iu->max_res_size = ZFCP_CT_MAX_SIZE;
-	fc_ct_iu->data.wwpn = erp_action->port->wwpn;
-
-	erp_action->fsf_req->data.send_generic.handler =
-	    zfcp_nameserver_request_handler;
-	erp_action->fsf_req->data.send_generic.handler_data =
-	    (unsigned long) erp_action->port;
-	erp_action->fsf_req->data.send_generic.port =
-	    erp_action->adapter->nameserver_port;
-	erp_action->fsf_req->erp_action = erp_action;
-
-	/* send this one */
-	retval = zfcp_fsf_send_generic(erp_action->fsf_req,
-				       ZFCP_NAMESERVER_TIMEOUT,
-				       &lock_flags,
-				       &erp_action->timer);
-	if (retval) {
-		ZFCP_LOG_INFO("error: Could not send a"
-			      "nameserver request command to adapter %s\n",
-			      zfcp_get_busid_by_adapter(erp_action->adapter));
-		goto failed_send;
+        if ((gid_pn->ct.pool != 0)) {
+		mempool_free(gid_pn, gid_pn->ct.pool);
+        } else {
+                kfree(gid_pn);
 	}
 
+	return;
+}
+
+/**
+ * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request
+ * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
+ */
+int
+zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
+{
+	int ret;
+        struct ct_iu_gid_pn_req *ct_iu_req;
+        struct zfcp_gid_pn_data *gid_pn;
+        struct zfcp_adapter *adapter = erp_action->adapter;
+
+	ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn);
+	if (ret < 0) {
+		ZFCP_LOG_INFO("error: Out of memory. Could not allocate "
+                              "buffers for nameserver request GID_PN. "
+                              "(adapter: %s)\n",
+			      zfcp_get_busid_by_adapter(adapter));
 	goto out;
+	}
 
- failed_send:
-	zfcp_release_nameserver_buffers(erp_action->fsf_req);
+	/* setup nameserver request */
+        ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req);
+        ct_iu_req->header.revision = ZFCP_CT_REVISION;
+        ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
+        ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
+        ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS;
+        ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN;
+        ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE;
+	ct_iu_req->wwpn = erp_action->port->wwpn;
+
+        /* setup parameters for send generic command */
+        gid_pn->ct.port = adapter->nameserver_port;
+	gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
+	gid_pn->ct.handler_data = (unsigned long) gid_pn;
+        gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
+        gid_pn->ct.timer = &erp_action->timer;
+	gid_pn->port = erp_action->port;
+
+	ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
+			       erp_action);
+	if (ret) {
+		ZFCP_LOG_INFO("error: Could not send nameserver request GID_PN."
+                              "(adapter %s)\n",
+			      zfcp_get_busid_by_adapter(adapter));
 
- failed_buffers:
-	zfcp_fsf_req_free(erp_action->fsf_req);
-	erp_action->fsf_req = NULL;
+                zfcp_gid_pn_buffers_free(gid_pn);
+	}
 
- failed_req:
  out:
-	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
-				lock_flags);
-	return retval;
+	return ret;
 }
 
-/*
- * function:	zfcp_nameserver_request_handler
- *
- * purpose:	
- *
- * returns:
+/**
+ * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request
+ * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data
  */
-static void
-zfcp_nameserver_request_handler(struct zfcp_fsf_req *fsf_req)
+static void zfcp_ns_gid_pn_handler(unsigned long data)
 {
-	struct fc_ct_iu *fc_ct_iu_resp =
-	    (struct fc_ct_iu *) (fsf_req->data.send_generic.inbuf);
-	struct fc_ct_iu *fc_ct_iu_req =
-	    (struct fc_ct_iu *) (fsf_req->data.send_generic.outbuf);
-	struct zfcp_port *port =
-	    (struct zfcp_port *) fsf_req->data.send_generic.handler_data;
+	struct zfcp_port *port;
+        struct zfcp_send_ct *ct;
+	struct ct_iu_gid_pn_req *ct_iu_req;
+	struct ct_iu_gid_pn_resp *ct_iu_resp;
+        struct zfcp_gid_pn_data *gid_pn;
+
 
-	if (fc_ct_iu_resp->revision != ZFCP_CT_REVISION)
+	gid_pn = (struct zfcp_gid_pn_data *) data;
+	port = gid_pn->port;
+        ct = &gid_pn->ct;
+	ct_iu_req = zfcp_sg_to_address(ct->req);
+	ct_iu_resp = zfcp_sg_to_address(ct->resp);
+
+        if (ct_iu_resp->header.revision != ZFCP_CT_REVISION)
 		goto failed;
-	if (fc_ct_iu_resp->gs_type != ZFCP_CT_DIRECTORY_SERVICE)
+        if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE)
 		goto failed;
-	if (fc_ct_iu_resp->gs_subtype != ZFCP_CT_NAME_SERVER)
+        if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER)
 		goto failed;
-	if (fc_ct_iu_resp->options != ZFCP_CT_SYNCHRONOUS)
+        if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
 		goto failed;
-	if (fc_ct_iu_resp->cmd_rsp_code != ZFCP_CT_ACCEPT) {
+        if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
 		/* FIXME: do we need some specific erp entry points */
 		atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
 		goto failed;
 	}
 	/* paranoia */
-	if (fc_ct_iu_req->data.wwpn != port->wwpn) {
-		ZFCP_LOG_NORMAL("bug: Port WWPN returned by nameserver lookup "
-				"does not correspond to "
-				"the expected value on the adapter %s. "
-				"(debug info 0x%Lx, 0x%Lx)\n",
-				zfcp_get_busid_by_port(port),
-				port->wwpn, fc_ct_iu_req->data.wwpn);
+	if (ct_iu_req->wwpn != port->wwpn) {
+		ZFCP_LOG_NORMAL(
+			"bug: Port WWPN returned by nameserver lookup "
+                        "does not correspond to the expected value "
+			"(adapter: %s, debug info: 0x%016Lx, 0x%016Lx)\n",
+			zfcp_get_busid_by_port(port), port->wwpn,
+                        ct_iu_req->wwpn);
 		goto failed;
 	}
 
 	/* looks like a valid d_id */
-	port->d_id = ZFCP_DID_MASK & fc_ct_iu_resp->data.d_id;
+        port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
 	atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
 	ZFCP_LOG_DEBUG("busid %s:  WWPN=0x%Lx ---> D_ID=0x%6.6x\n",
 		       zfcp_get_busid_by_port(port),
 		       port->wwpn, (unsigned int) port->d_id);
 	goto out;
 
- failed:
+failed:
 	ZFCP_LOG_NORMAL("warning: WWPN 0x%Lx not found by nameserver lookup "
-			"using the adapter %s\n",
+			"(adapter: %s)\n",
 			port->wwpn, zfcp_get_busid_by_port(port));
 	ZFCP_LOG_DEBUG("CT IUs do not match:\n");
-	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-		      (char *) fc_ct_iu_req, sizeof (struct fc_ct_iu));
-	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-		      (char *) fc_ct_iu_resp, sizeof (struct fc_ct_iu));
+	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req,
+		      sizeof(struct ct_iu_gid_pn_req));
+	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp,
+		      sizeof(struct ct_iu_gid_pn_resp));
 
  out:
-	zfcp_release_nameserver_buffers(fsf_req);
+        zfcp_gid_pn_buffers_free(gid_pn);
+	return;
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_ccw.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_ccw.c
--- 25/drivers/s390/scsi/zfcp_ccw.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_ccw.c	Fri Feb 20 16:00:58 2004
@@ -5,7 +5,8 @@
  *
  * CCW driver related routines
  *
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
  * Authors:
  *      Martin Peschke <mpeschke@de.ibm.com>
  *	Heiko Carstens <heiko.carstens@de.ibm.com>
@@ -25,7 +26,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_CCW_C_REVISION "$Revision: 1.36 $"
+#define ZFCP_CCW_C_REVISION "$Revision: 1.48 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -34,18 +35,22 @@
 #include "zfcp_def.h"
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_CONFIG
 
 static int zfcp_ccw_probe(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 *);
+static int zfcp_ccw_notify(struct ccw_device *, int);
 
 static struct ccw_device_id zfcp_ccw_device_id[] = {
 	{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
 			    ZFCP_CONTROL_UNIT_MODEL,
 			    ZFCP_DEVICE_TYPE,
 			    ZFCP_DEVICE_MODEL)},
+	{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
+			    ZFCP_CONTROL_UNIT_MODEL,
+			    ZFCP_DEVICE_TYPE,
+			    ZFCP_DEVICE_MODEL_PRIV)},
 	{},
 };
 
@@ -56,6 +61,7 @@ static struct ccw_driver zfcp_ccw_driver
 	.remove      = zfcp_ccw_remove,
 	.set_online  = zfcp_ccw_set_online,
 	.set_offline = zfcp_ccw_set_offline,
+	.notify      = zfcp_ccw_notify,
 };
 
 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -80,6 +86,9 @@ zfcp_ccw_probe(struct ccw_device *ccw_de
 	adapter = zfcp_adapter_enqueue(ccw_device);
 	if (!adapter)
 		retval = -EINVAL;
+	else
+		ZFCP_LOG_DEBUG("Probed adapter %s\n",
+			       zfcp_get_busid_by_adapter(adapter));
 	up(&zfcp_data.config_sema);
 	return retval;
 }
@@ -104,6 +113,8 @@ zfcp_ccw_remove(struct ccw_device *ccw_d
 	down(&zfcp_data.config_sema);
 	adapter = dev_get_drvdata(&ccw_device->dev);
 
+	ZFCP_LOG_DEBUG("Removing adapter %s\n",
+		       zfcp_get_busid_by_adapter(adapter));
 	write_lock_irq(&zfcp_data.config_lock);
 	list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
 		list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
@@ -152,13 +163,26 @@ zfcp_ccw_set_online(struct ccw_device *c
 	down(&zfcp_data.config_sema);
 	adapter = dev_get_drvdata(&ccw_device->dev);
 
+	retval = zfcp_erp_thread_setup(adapter);
+	if (retval) {
+		ZFCP_LOG_INFO("error: out of resources. "
+			      "error recovery thread for adapter %s "
+			      "could not be started\n",
+			      zfcp_get_busid_by_adapter(adapter));
+		goto out;
+	}
+
 	retval = zfcp_adapter_scsi_register(adapter);
 	if (retval)
-		goto out;
+		goto out_scsi_register;
 	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);
+	goto out;
+
+ out_scsi_register:
+	zfcp_erp_thread_kill(adapter);
  out:
 	up(&zfcp_data.config_sema);
 	return retval;
@@ -183,11 +207,50 @@ zfcp_ccw_set_offline(struct ccw_device *
 	zfcp_erp_adapter_shutdown(adapter, 0);
 	zfcp_erp_wait(adapter);
 	zfcp_adapter_scsi_unregister(adapter);
+	zfcp_erp_thread_kill(adapter);
 	up(&zfcp_data.config_sema);
 	return 0;
 }
 
 /**
+ * zfcp_ccw_notify
+ * @ccw_device: pointer to belonging ccw device
+ * @event: indicates if adapter was detached or attached
+ *
+ * This function gets called by the common i/o layer if an adapter has gone
+ * or reappeared.
+ */
+static int
+zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
+{
+	struct zfcp_adapter *adapter;
+
+	down(&zfcp_data.config_sema);
+	adapter = dev_get_drvdata(&ccw_device->dev);
+	switch (event) {
+	case CIO_GONE:
+		ZFCP_LOG_NORMAL("Adapter %s: device gone.\n",
+				zfcp_get_busid_by_adapter(adapter));
+		break;
+	case CIO_NO_PATH:
+		ZFCP_LOG_NORMAL("Adapter %s: no path.\n",
+				zfcp_get_busid_by_adapter(adapter));
+		break;
+	case CIO_OPER:
+		ZFCP_LOG_NORMAL("Adapter %s: operational again.\n",
+				zfcp_get_busid_by_adapter(adapter));
+		zfcp_erp_modify_adapter_status(adapter,
+					       ZFCP_STATUS_COMMON_RUNNING,
+					       ZFCP_SET);
+		zfcp_erp_adapter_reopen(adapter,
+					ZFCP_STATUS_COMMON_ERP_FAILED);
+		break;
+	}
+	up(&zfcp_data.config_sema);
+	return 1;
+}
+
+/**
  * zfcp_ccw_register - ccw register function
  *
  * Registers the driver at the common i/o layer. This function will be called
@@ -222,4 +285,3 @@ zfcp_ccw_unregister(void)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_def.h~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_def.h
--- 25/drivers/s390/scsi/zfcp_def.h~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_def.h	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  * 
  * FCP adapter driver for IBM eServer zSeries 
  * 
- * Copyright 2002 IBM Corporation 
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
- *            Aron Zeh <arzeh@de.ibm.com> 
- *            Wolfgang Taphorn <taphorn@de.ibm.com> 
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com> 
  *            Heiko Carstens <heiko.carstens@de.ibm.com> 
  * 
@@ -32,19 +33,29 @@
 #define ZFCP_DEF_H
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_DEF_REVISION "$Revision: 1.48 $"
+#define ZFCP_DEF_REVISION "$Revision: 1.62 $"
 
 /*************************** INCLUDES *****************************************/
 
 #include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
 #include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
 #include "../../fc4/fc.h"
 #include "zfcp_fsf.h"			/* FSF SW Interface */
 #include <asm/ccwdev.h>
 #include <asm/qdio.h>
 #include <asm/debug.h>
+#include <asm/ebcdic.h>
 #include <linux/reboot.h>
+#include <linux/mempool.h>
+#include <linux/ioctl.h>
+#ifdef CONFIG_S390_SUPPORT
+#include <linux/ioctl32.h>
+#endif
 
 /************************ DEBUG FLAGS *****************************************/
 
@@ -56,6 +67,24 @@
 #define	ZFCP_STAT_REQSIZES
 #define	ZFCP_STAT_QUEUES
 
+/********************* GENERAL DEFINES *********************************/
+
+/* zfcp version number, it consists of major, minor, and patch-level number */
+#define ZFCP_VERSION		"4.0.0"
+
+static inline void *
+zfcp_sg_to_address(struct scatterlist *list)
+{
+	return (void *) (page_address(list->page) + list->offset);
+}
+
+static inline void
+zfcp_address_to_sg(void *address, struct scatterlist *list)
+{
+	list->page = virt_to_page(address);
+	list->offset = ((unsigned long) address) & (PAGE_SIZE - 1);
+}
+
 /********************* SCSI SPECIFIC DEFINES *********************************/
 
 /* 32 bit for SCSI ID and LUN as long as the SCSI stack uses this type */
@@ -64,7 +93,6 @@ typedef u32 scsi_lun_t;
 
 #define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT           (100*HZ)
 #define ZFCP_SCSI_ER_TIMEOUT                    (100*HZ)
-#define ZFCP_SCSI_HOST_FLUSH_TIMEOUT            (1*HZ)
 
 /********************* CIO/QDIO SPECIFIC DEFINES *****************************/
 
@@ -73,9 +101,12 @@ typedef u32 scsi_lun_t;
 #define ZFCP_CONTROL_UNIT_MODEL 0x03
 #define ZFCP_DEVICE_TYPE        0x1732
 #define ZFCP_DEVICE_MODEL       0x03
+#define ZFCP_DEVICE_MODEL_PRIV	0x04
  
 /* allow as many chained SBALs as are supported by hardware */
 #define ZFCP_MAX_SBALS_PER_REQ		FSF_MAX_SBALS_PER_REQ
+#define ZFCP_MAX_SBALS_PER_CT_REQ	FSF_MAX_SBALS_PER_REQ
+#define ZFCP_MAX_SBALS_PER_ELS_REQ	FSF_MAX_SBALS_PER_ELS_REQ
 
 /* DMQ bug workaround: don't use last SBALE */
 #define ZFCP_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
@@ -115,9 +146,6 @@ typedef u32 scsi_lun_t;
 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES	6
 #define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP		50
 
-#define ZFCP_QTCB_SIZE		(sizeof(struct fsf_qtcb) + FSF_QTCB_LOG_SIZE)
-#define ZFCP_QTCB_AND_REQ_SIZE	(sizeof(struct zfcp_fsf_req) + ZFCP_QTCB_SIZE)
-
 /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
 
 typedef unsigned long long wwn_t;
@@ -129,7 +157,8 @@ typedef unsigned int       fcp_dl_t;
 #define ZFCP_FC_SERVICE_CLASS_DEFAULT	FSF_CLASS_3
 
 /* timeout for name-server lookup (in seconds) */
-#define ZFCP_NAMESERVER_TIMEOUT		10
+#define ZFCP_NS_GID_PN_TIMEOUT		10
+#define ZFCP_NS_GA_NXT_TIMEOUT		120
 
 /* largest SCSI command we can process */
 /* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */
@@ -241,33 +270,177 @@ struct fcp_logo {
         wwn_t nport_wwpn;
 } __attribute__((packed));
 
-struct fc_ct_iu {
-	u8	revision;	/* 0x01 */
-	u8	in_id[3];	/* 0x00 */
-	u8	gs_type;	/* 0xFC	Directory Service */
-	u8	gs_subtype;	/* 0x02	Name Server */
-	u8	options;	/* 0x10 synchronous/single exchange */
-	u8	reserved0;
-	u16	cmd_rsp_code;	/* 0x0121 GID_PN */
-	u16	max_res_size;	/* <= (4096 - 16) / 4 */
-	u8	reserved1;
+/*
+ * FC-FS stuff
+ */
+#define R_A_TOV				10 /* seconds */
+#define ZFCP_ELS_TIMEOUT		(2 * R_A_TOV)
+
+#define ZFCP_LS_RJT			0x01
+#define ZFCP_LS_ACC			0x02
+#define ZFCP_LS_RTV			0x0E
+#define ZFCP_LS_RLS			0x0F
+#define ZFCP_LS_PDISC			0x50
+#define ZFCP_LS_ADISC			0x52
+#define ZFCP_LS_RSCN			0x61
+#define ZFCP_LS_RNID			0x78
+#define ZFCP_LS_RLIR			0x7A
+#define ZFCP_LS_RTV_E_D_TOV_FLAG	0x04000000
+
+/* LS_ACC Reason Codes */
+#define ZFCP_LS_RJT_INVALID_COMMAND_CODE	0x01
+#define ZFCP_LS_RJT_LOGICAL_ERROR		0x03
+#define ZFCP_LS_RJT_LOGICAL_BUSY		0x05
+#define ZFCP_LS_RJT_PROTOCOL_ERROR		0x07
+#define ZFCP_LS_RJT_UNABLE_TO_PERFORM		0x09
+#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_code_expl;
+	u8		reason_expl;
 	u8	vendor_unique;
-	union {
+} __attribute__ ((packed));
+
+struct zfcp_ls_rtv {
+	u8		code;
+	u8		field[3];
+} __attribute__ ((packed));
+
+struct zfcp_ls_rtv_acc {
+	u8		code;
+	u8		field[3];
+	u32		r_a_tov;
+	u32		e_d_tov;
+	u32		qualifier;
+} __attribute__ ((packed));
+
+struct zfcp_ls_rls {
+	u8		code;
+	u8		field[3];
+	fc_id_t		port_id;
+} __attribute__ ((packed));
+
+struct zfcp_ls_rls_acc {
+	u8		code;
+	u8		field[3];
+	u32		link_failure_count;
+	u32		loss_of_sync_count;
+	u32		loss_of_signal_count;
+	u32		prim_seq_prot_error;
+	u32		invalid_transmition_word;
+	u32		invalid_crc_count;
+} __attribute__ ((packed));
+
+struct zfcp_ls_pdisc {
+	u8		code;
+	u8		field[3];
+	u8		common_svc_parm[16];
 		wwn_t	wwpn;
-		fc_id_t	d_id;
-	} data;
+	wwn_t		wwnn;
+	struct {
+		u8	class1[16];
+		u8	class2[16];
+		u8	class3[16];
+	} svc_parm;
+	u8		reserved[16];
+	u8		vendor_version[16];
+} __attribute__ ((packed));
+
+struct zfcp_ls_pdisc_acc {
+	u8		code;
+	u8		field[3];
+	u8		common_svc_parm[16];
+	wwn_t		wwpn;
+	wwn_t		wwnn;
+	struct {
+		u8	class1[16];
+		u8	class2[16];
+		u8	class3[16];
+	} svc_parm;
+	u8		reserved[16];
+	u8		vendor_version[16];
+} __attribute__ ((packed));
+
+struct zfcp_ls_adisc {
+	u8		code;
+	u8		field[3];
+	fc_id_t		hard_nport_id;
+	wwn_t		wwpn;
+	wwn_t		wwnn;
+	fc_id_t		nport_id;
+} __attribute__ ((packed));
+
+struct zfcp_ls_adisc_acc {
+	u8		code;
+	u8		field[3];
+	fc_id_t		hard_nport_id;
+	wwn_t		wwpn;
+	wwn_t		wwnn;
+	fc_id_t		nport_id;
 } __attribute__ ((packed));
 
+struct zfcp_ls_rnid {
+	u8		code;
+	u8		field[3];
+	u8		node_id_format;
+	u8		reserved[3];
+} __attribute__((packed));
+
+/* common identification data */
+struct zfcp_ls_rnid_common_id {
+	u64		n_port_name;
+	u64		node_name;
+} __attribute__((packed));
+
+/* general topology specific identification data */
+struct zfcp_ls_rnid_general_topology_id {
+	u8		vendor_unique[16];
+	u32		associated_type;
+	u32		physical_port_number;
+	u32		nr_attached_nodes;
+	u8		node_management;
+	u8		ip_version;
+	u16		port_number;
+	u8		ip_address[16];
+	u8		reserved[2];
+	u16		vendor_specific;
+} __attribute__((packed));
+
+struct zfcp_ls_rnid_acc {
+	u8		code;
+	u8		field[3];
+	u8		node_id_format;
+	u8		common_id_length;
+	u8		reserved;
+	u8		specific_id_length;
+	struct zfcp_ls_rnid_common_id
+			common_id;
+	struct zfcp_ls_rnid_general_topology_id
+			specific_id;
+} __attribute__((packed));
+
+/*
+ * FC-GS-2 stuff
+ */
 #define ZFCP_CT_REVISION		0x01
 #define ZFCP_CT_DIRECTORY_SERVICE	0xFC
 #define ZFCP_CT_NAME_SERVER		0x02
 #define ZFCP_CT_SYNCHRONOUS		0x00
 #define ZFCP_CT_GID_PN			0x0121
+#define ZFCP_CT_GA_NXT			0x0100
 #define ZFCP_CT_MAX_SIZE		0x1020
 #define ZFCP_CT_ACCEPT			0x8002
 
+/*
+ * FC-GS-4 stuff
+ */
+#define ZFCP_CT_TIMEOUT			(3 * R_A_TOV)
+
+
 /***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/
 
 /* debug feature entries per adapter */
@@ -333,16 +506,6 @@ struct fc_ct_iu {
 #define ZFCP_LOG_LEVEL_DEBUG	2
 #define ZFCP_LOG_LEVEL_TRACE	3
 
-/* default log levels for different log areas */
-#define ZFCP_LOG_LEVEL_DEFAULT_OTHER	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_SCSI	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_FSF	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_CONFIG	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_CIO	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_QDIO	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_ERP	ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_LEVEL_DEFAULT_FC	ZFCP_LOG_LEVEL_INFO
-
 /*
  * this allows removal of logging code by the preprocessor
  * (the most detailed log level still to be compiled in is specified, 
@@ -350,93 +513,75 @@ struct fc_ct_iu {
  */
 #define ZFCP_LOG_LEVEL_LIMIT	ZFCP_LOG_LEVEL_TRACE
 
-/* positional "loglevel" nibble assignment */
-#define ZFCP_LOG_VALUE(zfcp_lognibble) \
+/* get "loglevel" nibble assignment */
+#define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \
 	       ((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF)
 
-#define ZFCP_LOG_VALUE_OTHER	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_OTHER)
-#define ZFCP_LOG_VALUE_SCSI	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_SCSI)
-#define ZFCP_LOG_VALUE_FSF	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FSF)
-#define ZFCP_LOG_VALUE_CONFIG	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_CONFIG)
-#define ZFCP_LOG_VALUE_CIO	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_CIO)
-#define ZFCP_LOG_VALUE_QDIO	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_QDIO)
-#define ZFCP_LOG_VALUE_ERP	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_ERP)
-#define ZFCP_LOG_VALUE_FC	ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FC)
+/* set "loglevel" nibble */
+#define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \
+	       (value << (zfcp_lognibble << 2))
 
 /* all log-level defaults are combined to generate initial log-level */
 #define ZFCP_LOG_LEVEL_DEFAULTS \
-	((ZFCP_LOG_LEVEL_DEFAULT_OTHER	<< (ZFCP_LOG_AREA_OTHER<<2))	| \
-	 (ZFCP_LOG_LEVEL_DEFAULT_SCSI	<< (ZFCP_LOG_AREA_SCSI<<2))	| \
-	 (ZFCP_LOG_LEVEL_DEFAULT_FSF	<< (ZFCP_LOG_AREA_FSF<<2))	| \
-	 (ZFCP_LOG_LEVEL_DEFAULT_CONFIG	<< (ZFCP_LOG_AREA_CONFIG<<2))	| \
-	 (ZFCP_LOG_LEVEL_DEFAULT_CIO	<< (ZFCP_LOG_AREA_CIO<<2))	| \
-	 (ZFCP_LOG_LEVEL_DEFAULT_QDIO	<< (ZFCP_LOG_AREA_QDIO<<2))	| \
-	 (ZFCP_LOG_LEVEL_DEFAULT_ERP	<< (ZFCP_LOG_AREA_ERP<<2))      | \
-	 (ZFCP_LOG_LEVEL_DEFAULT_FC	<< (ZFCP_LOG_AREA_FC<<2)))
-
-/* the prefix placed at the beginning of each driver message */
-#define ZFCP_LOG_PREFIX ZFCP_NAME": "
-
-/* log area specific prefixes */
-#define ZFCP_LOG_AREA_PREFIX_OTHER	""
-#define ZFCP_LOG_AREA_PREFIX_SCSI	"SCSI: "
-#define ZFCP_LOG_AREA_PREFIX_FSF	"FSF: "
-#define ZFCP_LOG_AREA_PREFIX_CONFIG	"config: "
-#define ZFCP_LOG_AREA_PREFIX_CIO	"common I/O: "
-#define ZFCP_LOG_AREA_PREFIX_QDIO	"QDIO: "
-#define ZFCP_LOG_AREA_PREFIX_ERP	"ERP: "
-#define ZFCP_LOG_AREA_PREFIX_FC 	"FC: "
+	(ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_OTHER) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_SCSI) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FSF) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CONFIG) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CIO) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_QDIO) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_ERP) | \
+	 ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FC))
 
 /* check whether we have the right level for logging */
-#define ZFCP_LOG_CHECK(ll)	(ZFCP_LOG_VALUE(ZFCP_LOG_AREA)) >= ll
+#define ZFCP_LOG_CHECK(level) \
+	((ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA)) >= level)
 
-/* As we have two printks it is possible for them to be seperated by another
- * message. This holds true even for printks from within this module.
- * In any case there should only be a small readability hit, however.
- */
-#define _ZFCP_LOG(m...) \
-		{ \
-			printk( "%s%s: ", \
-				ZFCP_LOG_PREFIX ZFCP_LOG_AREA_PREFIX, \
-				__FUNCTION__); \
-			printk(m); \
-		}
-
-#define ZFCP_LOG(ll, m...) \
-		if (ZFCP_LOG_CHECK(ll)) \
-			_ZFCP_LOG(m)
+/* logging routine for zfcp */
+#define _ZFCP_LOG(fmt, args...) \
+	printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __FUNCTION__, \
+	       __LINE__ , ##args);
+
+#define ZFCP_LOG(level, fmt, args...) \
+	if (ZFCP_LOG_CHECK(level)) \
+		_ZFCP_LOG(fmt , ##args)
 	
 #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
-#define ZFCP_LOG_NORMAL(m...)
-#else	/* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_NORMAL */
-#define ZFCP_LOG_NORMAL(m...)		ZFCP_LOG(ZFCP_LOG_LEVEL_NORMAL, m)
+# define ZFCP_LOG_NORMAL(fmt, args...)
+#else
+# define ZFCP_LOG_NORMAL(fmt, args...) \
+	if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \
+		printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
 #endif
 
 #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO
-#define ZFCP_LOG_INFO(m...)
-#else	/* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_INFO */
-#define ZFCP_LOG_INFO(m...)		ZFCP_LOG(ZFCP_LOG_LEVEL_INFO, m)
+# define ZFCP_LOG_INFO(fmt, args...)
+#else
+# define ZFCP_LOG_INFO(fmt, args...) \
+	if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \
+		printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
 #endif
 
 #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG
-#define ZFCP_LOG_DEBUG(m...)
-#else	/* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_DEBUG */
-#define ZFCP_LOG_DEBUG(m...)		ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, m)
+# define ZFCP_LOG_DEBUG(fmt, args...)
+#else
+# define ZFCP_LOG_DEBUG(fmt, args...) \
+	ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args)
 #endif
 
 #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE
-#define ZFCP_LOG_TRACE(m...)
-#else	/* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_TRACE */
-#define ZFCP_LOG_TRACE(m...)		ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, m)
+# define ZFCP_LOG_TRACE(fmt, args...)
+#else
+# define ZFCP_LOG_TRACE(fmt, args...) \
+	ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
 #endif
 
-#ifdef ZFCP_PRINT_FLAGS
-extern u32 flags_dump;
-#define ZFCP_LOG_FLAGS(ll, m...) \
-		if (ll<=flags_dump) \
-			_ZFCP_LOG(m)
+#ifndef ZFCP_PRINT_FLAGS
+# define ZFCP_LOG_FLAGS(level, fmt, args...)
 #else
-#define ZFCP_LOG_FLAGS(ll, m...)
+extern u32 flags_dump;
+# define ZFCP_LOG_FLAGS(level, fmt, args...) \
+	if (level <= flags_dump) \
+		_ZFCP_LOG(fmt , ##args)
 #endif
 
 /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
@@ -506,19 +651,19 @@ extern u32 flags_dump;
 #define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP        0x00000400
 #define ZFCP_STATUS_FSFREQ_RETRY                0x00000800
 #define ZFCP_STATUS_FSFREQ_DISMISSED            0x00001000
-#define ZFCP_STATUS_FSFREQ_POOLBUF              0x00002000
 
 /*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/
 
 #define ZFCP_MAX_ERPS                   3
 
-#define ZFCP_ERP_FSFREQ_TIMEOUT		(100 * HZ)
+#define ZFCP_ERP_FSFREQ_TIMEOUT		(30 * HZ)
 #define ZFCP_ERP_MEMWAIT_TIMEOUT	HZ
 
 #define ZFCP_STATUS_ERP_TIMEDOUT	0x10000000
 #define ZFCP_STATUS_ERP_CLOSE_ONLY	0x01000000
 #define ZFCP_STATUS_ERP_DISMISSING	0x00100000
 #define ZFCP_STATUS_ERP_DISMISSED	0x00200000
+#define ZFCP_STATUS_ERP_LOWMEM		0x00400000
 
 #define ZFCP_ERP_STEP_UNINITIALIZED	0x00000000
 #define ZFCP_ERP_STEP_FSF_XCONFIG	0x00000001
@@ -546,19 +691,55 @@ extern u32 flags_dump;
 #define ZFCP_ERP_DISMISSED	0x4
 #define ZFCP_ERP_NOMEM		0x5
 
-/************************* STRUCTURE DEFINITIONS *****************************/
 
+/******************** CFDC SPECIFIC STUFF *****************************/
+
+/* Firewall data channel sense data record */
+struct zfcp_cfdc_sense_data {
+	u32 signature;           /* Request signature */
+	u32 devno;               /* FCP adapter device number */
+	u32 command;             /* Command code */
+	u32 fsf_status;          /* FSF request status and status qualifier */
+	u8  fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+	u8  payloads[256];       /* Access conflicts list */
+	u8  control_file[0];     /* Access control table */
+};
+
+#define ZFCP_CFDC_SIGNATURE			0xCFDCACDF
+
+#define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL		0x00010001
+#define ZFCP_CFDC_CMND_DOWNLOAD_FORCE		0x00010101
+#define ZFCP_CFDC_CMND_FULL_ACCESS		0x00000201
+#define ZFCP_CFDC_CMND_RESTRICTED_ACCESS	0x00000401
+#define ZFCP_CFDC_CMND_UPLOAD			0x00010002
+
+#define ZFCP_CFDC_DOWNLOAD			0x00000001
+#define ZFCP_CFDC_UPLOAD			0x00000002
+#define ZFCP_CFDC_WITH_CONTROL_FILE		0x00010000
+
+#define ZFCP_CFDC_DEV_NAME			"zfcp_cfdc"
+#define ZFCP_CFDC_DEV_MAJOR			MISC_MAJOR
+#define ZFCP_CFDC_DEV_MINOR			MISC_DYNAMIC_MINOR
+
+#define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE		127 * 1024
+
+static const char zfcp_act_subtable_type[5][8] = {
+	{"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
+};
+
+
+/************************* STRUCTURE DEFINITIONS *****************************/
 
 struct zfcp_fsf_req;
-typedef void zfcp_send_generic_handler_t(struct zfcp_fsf_req*);
 
+/* holds various memory pools of an adapter */
 struct zfcp_adapter_mempool {
-        mempool_t *status_read_fsf;
-	mempool_t *status_read_buf;
-        mempool_t *nameserver;
-        mempool_t *erp_fsf;
-        mempool_t *fcp_command_fsf;
-        struct timer_list fcp_command_fsf_timer;
+	mempool_t *fsf_req_erp;
+	mempool_t *fsf_req_scsi;
+	mempool_t *fsf_req_abort;
+	mempool_t *fsf_req_status_read;
+	mempool_t *data_status_read;
+	mempool_t *data_gid_pn;
 };
 
 struct  zfcp_exchange_config_data{
@@ -587,7 +768,7 @@ struct zfcp_close_physical_port {
 struct zfcp_send_fcp_command_task {
 	struct zfcp_fsf_req *fsf_req;
 	struct zfcp_unit *unit;
- 	Scsi_Cmnd *scsi_cmnd;
+ 	struct scsi_cmnd *scsi_cmnd;
 	unsigned long start_jiffies;
 };
 
@@ -600,20 +781,119 @@ struct zfcp_abort_fcp_command {
 	struct zfcp_unit *unit;
 };
 
-struct zfcp_send_generic {
+/*
+ * header for CT_IU
+ */
+struct ct_hdr {
+	u8 revision;		// 0x01
+	u8 in_id[3];		// 0x00
+	u8 gs_type;		// 0xFC	Directory Service
+	u8 gs_subtype;		// 0x02	Name Server
+	u8 options;		// 0x00 single bidirectional exchange
+	u8 reserved0;
+	u16 cmd_rsp_code;	// 0x0121 GID_PN, or 0x0100 GA_NXT
+	u16 max_res_size;	// <= (4096 - 16) / 4
+	u8 reserved1;
+	u8 reason_code;
+	u8 reason_code_expl;
+	u8 vendor_unique;
+} __attribute__ ((packed));
+
+/* nameserver request CT_IU -- for requests where
+ * a port name is required */
+struct ct_iu_gid_pn_req {
+	struct ct_hdr header;
+	wwn_t wwpn;
+} __attribute__ ((packed));
+
+/* nameserver request CT_IU -- for requests where
+ * a port identifier is required */
+struct ct_iu_ga_nxt_req {
+	struct ct_hdr header;
+	fc_id_t d_id;
+} __attribute__ ((packed));
+
+/* FS_ACC IU and data unit for GID_PN nameserver request */
+struct ct_iu_gid_pn_resp {
+	struct ct_hdr header;
+	fc_id_t d_id;
+} __attribute__ ((packed));
+
+/* FS_ACC IU and data unit for GA_NXT nameserver request */
+struct ct_iu_ga_nxt_resp {
+	struct ct_hdr header;
+        u8 port_type;
+        u8 port_id[3];
+        u64 port_wwn;
+        u8 port_symbolic_name_length;
+        u8 port_symbolic_name[255];
+        u64 node_wwn;
+        u8 node_symbolic_name_length;
+        u8 node_symbolic_name[255];
+        u64 initial_process_associator;
+        u8 node_ip[16];
+        u32 cos;
+        u8 fc4_types[32];
+        u8 port_ip[16];
+        u64 fabric_wwn;
+        u8 reserved;
+        u8 hard_address[3];
+} __attribute__ ((packed));
+
+typedef void (*zfcp_send_ct_handler_t)(unsigned long);
+
+/* used to pass parameters to zfcp_send_ct() */
+struct zfcp_send_ct {
+	struct zfcp_port *port;
+	struct scatterlist *req;
+	struct scatterlist *resp;
+	unsigned int req_count;
+	unsigned int resp_count;
+	zfcp_send_ct_handler_t handler;
+	unsigned long handler_data;
+	mempool_t *pool;		/* mempool for ct not for fsf_req */
+	int timeout;
+	struct timer_list *timer;
+	struct completion *completion;
+	int status;
+};
+
+/* used for name server requests in error recovery */
+struct zfcp_gid_pn_data {
+	struct zfcp_send_ct ct;
+	struct scatterlist req;
+	struct scatterlist resp;
+	struct ct_iu_gid_pn_req ct_iu_req;
+	struct ct_iu_gid_pn_resp ct_iu_resp;
         struct zfcp_port *port;
-	char *outbuf;
-	char *inbuf;
-	int outbuf_length;
-	int inbuf_length;
-	zfcp_send_generic_handler_t *handler;
+};
+
+typedef int (*zfcp_send_els_handler_t)(unsigned long);
+
+/* used to pass parameters to zfcp_send_els() */
+/* ToDo merge send_ct() and send_els() and corresponding structs */
+struct zfcp_send_els {
+	struct zfcp_port *port;
+	struct scatterlist *req;
+	struct scatterlist *resp;
+	unsigned int req_count;
+	unsigned int resp_count;
+	zfcp_send_els_handler_t handler;
 	unsigned long handler_data;
+	struct completion *completion;
+	int ls_code;
+	int status;
 };
 
 struct zfcp_status_read {
 	struct fsf_status_read_buffer *buffer;
 };
 
+struct zfcp_fsf_done {
+	struct completion *complete;
+	int status;
+};
+
 /* request specific data */
 union zfcp_req_data {
 	struct zfcp_exchange_config_data exchange_config_data;
@@ -626,7 +906,8 @@ union zfcp_req_data {
         struct zfcp_send_fcp_command_task_management
 					  send_fcp_command_task_management;
 	struct zfcp_abort_fcp_command	  abort_fcp_command;
-	struct zfcp_send_generic	  send_generic;
+	struct zfcp_send_ct *send_ct;
+	struct zfcp_send_els *send_els;
 	struct zfcp_status_read 	  status_read;
 };
 
@@ -671,6 +952,9 @@ struct zfcp_adapter {
 	u32			fc_link_speed;	   /* FC interface speed */
 	u32			hydra_version;	   /* Hydra version */
 	u32			fsf_lic_version;
+        u32			supported_features;/* of FCP channel */
+        u32			hardware_version;  /* of FCP channel */
+        u8			serial_number[32]; /* of hardware */
 	struct Scsi_Host	*scsi_host;	   /* Pointer to mid-layer */
 
 	unsigned char		name[9];
@@ -704,6 +988,10 @@ struct zfcp_adapter {
 	wait_queue_head_t	erp_done_wqh;
 	struct zfcp_erp_action	erp_action;	   /* pending error recovery */
         atomic_t                erp_counter;
+	u32			erp_total_count;   /* total nr of enqueued erp
+						      actions */
+	u32			erp_low_mem_count; /* nr of erp actions waiting
+						      for memory */
 	struct zfcp_port	*nameserver_port;  /* adapter's nameserver */
         debug_info_t            *erp_dbf;          /* S/390 debug features */
 	debug_info_t            *abort_dbf;
@@ -751,7 +1039,7 @@ struct zfcp_unit {
 	scsi_lun_t	       scsi_lun;       /* own SCSI LUN */
 	fcp_lun_t	       fcp_lun;	       /* own FCP_LUN */
 	u32		       handle;	       /* handle assigned by FSF */
-        Scsi_Device            *device;        /* scsi device struct pointer */
+        struct scsi_device     *device;        /* scsi device struct pointer */
 	struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
 	struct device          sysfs_device;   /* sysfs device */
@@ -765,8 +1053,14 @@ struct zfcp_fsf_req {
 	u32		       specific_magic; /* structure specific magic */
 	struct list_head       list;	       /* list of FSF requests */
 	struct zfcp_adapter    *adapter;       /* adapter request belongs to */
-	u8		       sbal_count;     /* # of SBALs in FSF request */
-	u8		       sbal_index;     /* position of 1st SBAL */
+	u8		       sbal_number;    /* nr of SBALs free for use */
+	u8		       sbal_first;     /* first SBAL for this request */
+	u8		       sbal_last;      /* last possible SBAL for
+						  this reuest */
+	u8		       sbal_curr;      /* current SBAL during creation
+						  of request */
+	u8		       sbale_curr;     /* current SBALE during creation
+						  of request */
 	wait_queue_head_t      completion_wq;  /* can be used by a routine
 						  to wait for completion */
 	volatile u32	       status;	       /* status of this request */
@@ -776,13 +1070,15 @@ struct zfcp_fsf_req {
         union zfcp_req_data    data;           /* Info fields of request */ 
 	struct zfcp_erp_action *erp_action;    /* used if this request is
 						  issued on behalf of erp */
+	mempool_t	       *pool;	       /* used if request was alloacted
+						  from emergency pool */
 };
 
 typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
 
 /* driver data */
 struct zfcp_data {
-	Scsi_Host_Template	scsi_host_template;
+	struct scsi_host_template scsi_host_template;
         atomic_t                status;             /* Module status flags */
 	struct list_head	adapter_list_head;  /* head of adapter list */
 	struct list_head	adapter_remove_lh;  /* head of adapters to be
@@ -792,7 +1088,7 @@ struct zfcp_data {
         struct list_head        status_read_send_head;
         struct semaphore        status_read_sema;
 	wait_queue_head_t	status_read_thread_wqh;
-	u16			adapters;	    /* # of adapters in list */
+	u32			adapters;	    /* # of adapters in list */
 	rwlock_t                config_lock;        /* serialises changes
 						       to adapter/port/unit
 						       lists */
@@ -829,6 +1125,24 @@ struct zfcp_statistics {
 };
 #endif
 
+struct zfcp_sg_list {
+	struct scatterlist *sg;
+	unsigned int count;
+};
+
+/* number of elements for various memory pools */
+#define ZFCP_POOL_FSF_REQ_ERP_NR	1
+#define ZFCP_POOL_FSF_REQ_SCSI_NR	1
+#define ZFCP_POOL_FSF_REQ_ABORT_NR	1
+#define ZFCP_POOL_STATUS_READ_NR	ZFCP_STATUS_READS_RECOM
+#define ZFCP_POOL_DATA_GID_PN_NR	1
+
+/* struct used by memory pools for fsf_requests */
+struct zfcp_fsf_req_pool_element {
+	struct zfcp_fsf_req fsf_req;
+	struct fsf_qtcb qtcb;
+};
+
 /********************** ZFCP SPECIFIC DEFINES ********************************/
 
 #define ZFCP_FSFREQ_CLEANUP_TIMEOUT	HZ/10
@@ -836,6 +1150,7 @@ struct zfcp_statistics {
 #define ZFCP_KNOWN              0x00000001
 #define ZFCP_REQ_AUTO_CLEANUP	0x00000002
 #define ZFCP_WAIT_FOR_SBAL	0x00000004
+#define ZFCP_REQ_NO_QTCB	0x00000008
 
 #define ZFCP_SET                0x00000100
 #define ZFCP_CLEAR              0x00000200
diff -puN drivers/s390/scsi/zfcp_erp.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_erp.c
--- 25/drivers/s390/scsi/zfcp_erp.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_erp.c	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  * 
  * FCP adapter driver for IBM eServer zSeries 
  * 
- * Copyright 2002 IBM Corporation 
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
- *            Aron Zeh <arzeh@de.ibm.com> 
- *            Wolfgang Taphorn <taphorn@de.ibm.com> 
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com> 
  *            Heiko Carstens <heiko.carstens@de.ibm.com> 
  * 
@@ -28,12 +29,15 @@
  */
 
 #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.39 $"
+#define ZFCP_ERP_REVISION "$Revision: 1.44 $"
 
 #include "zfcp_ext.h"
 
+static int zfcp_els(struct zfcp_port *, u8);
+static int zfcp_els_handler(unsigned long);
+
 static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int);
 static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int);
 static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int);
@@ -326,6 +330,375 @@ zfcp_erp_unit_shutdown(struct zfcp_unit 
 	return retval;
 }
 
+
+/*
+ * function:    zfcp_els
+ *
+ * purpose:     Originator of the ELS commands
+ *
+ * returns:     0       - Operation completed successfuly
+ *              -EINVAL - Unknown IOCTL command or invalid sense data record
+ *              -ENOMEM - Insufficient memory
+ *              -EPERM  - Cannot create or queue FSF request
+ */
+int
+zfcp_els(struct zfcp_port *port, u8 ls_code)
+{
+	struct zfcp_send_els *send_els;
+	struct zfcp_ls_rls *rls;
+	struct zfcp_ls_pdisc *pdisc;
+	struct zfcp_ls_adisc *adisc;
+	struct page *page = NULL;
+	void *req;
+	int retval = 0;
+
+	send_els = kmalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
+	if (send_els == NULL)
+		goto nomem;
+
+	send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+	if (send_els->req == NULL)
+		goto nomem;
+	send_els->req_count = 1;
+
+	send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+	if (send_els->resp == NULL)
+		goto nomem;
+	send_els->resp_count = 1;
+
+	page = alloc_pages(GFP_ATOMIC, 0);
+	if (page == NULL)
+		goto nomem;
+	send_els->req->page = page;
+	send_els->resp->page = page;
+	send_els->req->offset = 0;
+	send_els->resp->offset = PAGE_SIZE >> 1;
+
+	send_els->port = port;
+	send_els->ls_code = ls_code;
+	send_els->handler = zfcp_els_handler;
+	send_els->handler_data = (unsigned long)send_els;
+	send_els->completion = NULL;
+
+	req = zfcp_sg_to_address(send_els->req);
+
+	*(u32*)req = 0;
+	*(u8*)req = ls_code;
+
+	switch (ls_code) {
+
+	case ZFCP_LS_RTV:
+		send_els->req->length = sizeof(struct zfcp_ls_rtv);
+		send_els->resp->length = sizeof(struct zfcp_ls_rtv_acc);
+		ZFCP_LOG_NORMAL(
+			"RTV request from sid 0x%06x to did 0x%06x\n",
+			port->adapter->s_id, port->d_id);
+		break;
+
+	case ZFCP_LS_RLS:
+		send_els->req->length = sizeof(struct zfcp_ls_rls);
+		send_els->resp->length = sizeof(struct zfcp_ls_rls_acc);
+		rls = (struct zfcp_ls_rls*)req;
+		rls->port_id = port->adapter->s_id;
+		ZFCP_LOG_NORMAL(
+			"RLS request from sid 0x%06x to did 0x%06x "
+			"with payload(port_id=0x%06x)\n",
+			port->adapter->s_id, port->d_id, rls->port_id);
+		break;
+
+	case ZFCP_LS_PDISC:
+		send_els->req->length = sizeof(struct zfcp_ls_pdisc);
+		send_els->resp->length = sizeof(struct zfcp_ls_pdisc_acc);
+		pdisc = (struct zfcp_ls_pdisc*)req;
+		pdisc->wwpn = port->adapter->wwpn;
+		pdisc->wwnn = port->adapter->wwnn;
+		ZFCP_LOG_NORMAL(
+			"PDISC request from sid 0x%06x to did 0x%06x "
+			"with payload(wwpn=0x%016Lx wwnn=0x%016Lx)\n",
+			port->adapter->s_id, port->d_id,
+			pdisc->wwpn, pdisc->wwnn);
+		break;
+
+	case ZFCP_LS_ADISC:
+		send_els->req->length = sizeof(struct zfcp_ls_adisc);
+		send_els->resp->length = sizeof(struct zfcp_ls_adisc_acc);
+		adisc = (struct zfcp_ls_adisc*)req;
+		adisc->hard_nport_id = port->adapter->s_id;
+		adisc->wwpn = port->adapter->wwpn;
+		adisc->wwnn = port->adapter->wwnn;
+		adisc->nport_id = port->adapter->s_id;
+		ZFCP_LOG_NORMAL(
+			"ADISC request from sid 0x%06x to did 0x%06x "
+			"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
+			"hard_nport_id=0x%06x nport_id=0x%06x)\n",
+			port->adapter->s_id, port->d_id,
+			adisc->wwpn, adisc->wwnn,
+			adisc->hard_nport_id, adisc->nport_id);
+		break;
+
+	default:
+		ZFCP_LOG_NORMAL(
+			"ELS command code 0x%02x is not supported\n", ls_code);
+		retval = -EINVAL;
+		goto invalid_ls_code;
+	}
+
+	retval = zfcp_fsf_send_els(send_els);
+	if (retval != 0) {
+		ZFCP_LOG_NORMAL(
+			"ELS request could not be processed "
+			"(sid=0x%06x did=0x%06x)\n",
+			port->adapter->s_id, port->d_id);
+		retval = -EPERM;
+	}
+
+	goto out;
+
+nomem:
+	ZFCP_LOG_INFO("Out of memory!\n");
+	retval = -ENOMEM;
+
+invalid_ls_code:
+	if (page != NULL)
+		__free_pages(page, 0);
+	if (send_els != NULL) {
+		if (send_els->req != NULL)
+			kfree(send_els->req);
+		if (send_els->resp != NULL)
+			kfree(send_els->resp);
+		kfree(send_els);
+	}
+
+out:
+	return retval;
+}
+
+
+/*
+ * 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
+ */
+int
+zfcp_els_handler(unsigned long data)
+{
+	struct zfcp_send_els *send_els = (struct zfcp_send_els*)data;
+	struct zfcp_port *port = send_els->port;
+	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;
+	void *req, *resp;
+	u8 req_code, resp_code;
+	int retval = 0;
+
+	if (send_els->status != 0)
+		goto skip_fsfstatus;
+
+	req = (void*)((page_to_pfn(send_els->req->page) << PAGE_SHIFT) + send_els->req->offset);
+	resp = (void*)((page_to_pfn(send_els->resp->page) << PAGE_SHIFT) + send_els->resp->offset);
+	req_code = *(u8*)req;
+	resp_code = *(u8*)resp;
+
+	switch (resp_code) {
+
+	case ZFCP_LS_RJT:
+		rjt = (struct zfcp_ls_rjt*)resp;
+
+		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 by remote port "
+				"with WWPN 0x%Lx on the adapter %s "
+				"with the reason code 0x%02x\n",
+				port->wwpn, zfcp_get_busid_by_port(port),
+				rjt->reason_code);
+		}
+		retval = -ENXIO;
+		break;
+
+	case ZFCP_LS_ACC:
+		switch (req_code) {
+
+		case ZFCP_LS_RTV:
+			rtv = (struct zfcp_ls_rtv_acc*)resp;
+			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;
+
+		case ZFCP_LS_RLS:
+			rls = (struct zfcp_ls_rls_acc*)resp;
+			ZFCP_LOG_NORMAL(
+				"RLS response from did 0x%06x to sid 0x%06x "
+				"with payload(link_failure_count=%u "
+				"loss_of_sync_count=%u "
+				"loss_of_signal_count=%u "
+				"primitive_sequence_protocol_error=%u "
+				"invalid_transmition_word=%u "
+				"invalid_crc_count=%u)\n",
+				port->d_id, port->adapter->s_id,
+				rls->link_failure_count,
+				rls->loss_of_sync_count,
+				rls->loss_of_signal_count,
+				rls->prim_seq_prot_error,
+				rls->invalid_transmition_word,
+				rls->invalid_crc_count);
+			break;
+
+		case ZFCP_LS_PDISC:
+			pdisc = (struct zfcp_ls_pdisc_acc*)resp;
+			ZFCP_LOG_NORMAL(
+				"PDISC response from did 0x%06x to sid 0x%06x "
+				"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
+				"vendor='%-16s')\n",
+				port->d_id, port->adapter->s_id,
+				(unsigned long long)pdisc->wwpn,
+				(unsigned long long)pdisc->wwnn,
+				pdisc->vendor_version);
+			break;
+
+		case ZFCP_LS_ADISC:
+			adisc = (struct zfcp_ls_adisc_acc*)resp;
+			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",
+				port->d_id, port->adapter->s_id,
+				(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->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 "
+				"with WWPN 0x%Lx on the adapter %s\n",
+				port->wwpn, zfcp_get_busid_by_port(port));
+			retval = -EPERM;
+		}
+	}
+
+skip_fsfstatus:
+	__free_pages(send_els->req->page, 0);
+	kfree(send_els->req);
+	kfree(send_els->resp);
+
+	return retval;
+}
+
+
+/*
+ * function:    zfcp_test_link
+ *
+ * purpose:     Test a status of a link to a remote port using the ELS command ADISC
+ *
+ * returns:     0       - Link is OK
+ *              -EPERM  - Port forced reopen failed
+ */
+int
+zfcp_test_link(struct zfcp_port *port)
+{
+	int retval;
+
+	retval = zfcp_els(port, ZFCP_LS_ADISC);
+	if (retval != 0) {
+		ZFCP_LOG_NORMAL(
+			"Port with WWPN 0x%Lx on the adapter %s "
+			"needs to be reopened\n",
+			port->wwpn, zfcp_get_busid_by_port(port));
+		retval = zfcp_erp_port_forced_reopen(port, 0);
+		if (retval != 0) {
+			ZFCP_LOG_NORMAL(
+				"Cannot reopen a remote port "
+				"with WWPN 0x%Lx on the adapter %s\n",
+				port->wwpn, zfcp_get_busid_by_port(port));
+			retval = -EPERM;
+		}
+	}
+
+	return retval;
+}
+
+
 /*
  * function:	
  *
@@ -741,37 +1114,27 @@ zfcp_erp_strategy_check_fsfreq(struct zf
 						 "a_ca_disreq");
 				fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
 			}
+			if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+				ZFCP_LOG_NORMAL
+					("error: Error Recovery Procedure "
+					 "step timed out. The action flag "
+					 "is 0x%x. The FSF request "
+					 "is at 0x%lx\n",
+					 erp_action->action,
+					 (unsigned long)
+					 erp_action->fsf_req);
+			}
 			/*
 			 * If fsf_req is neither dismissed nor completed
-			 * then keep it running asynchronously and don't mess with
-			 * the association of erp_action and fsf_req.
+			 * then keep it running asynchronously and don't mess
+			 * with the association of erp_action and fsf_req.
 			 */
 			if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
 					       ZFCP_STATUS_FSFREQ_DISMISSED)) {
-				/* forget about association between fsf_req and erp_action */
+				/* forget about association between fsf_req
+				   and erp_action */
 				fsf_req->erp_action = NULL;
 				erp_action->fsf_req = NULL;
-				/* some special things for time out conditions */
-				if (erp_action-> status & ZFCP_STATUS_ERP_TIMEDOUT) {
-					ZFCP_LOG_NORMAL
-					    ("error: Error Recovery Procedure step timed out. "
-					     "The action flag is 0x%x. The FSF request "
-					     "is at 0x%lx\n", erp_action->action,
-					     (unsigned long) erp_action->fsf_req);
-					/* fight for low memory buffer, if required */
-					if (fsf_req->
-					    status & ZFCP_STATUS_FSFREQ_POOL) {
-						debug_text_event(adapter->erp_dbf, 3,
-								 "a_ca_lowmem");
-						ZFCP_LOG_NORMAL
-						    ("error: The error recovery action using the "
-						     "low memory pool timed out. Restarting IO on "
-						     "the adapter %s to free it.\n",
-						     zfcp_get_busid_by_adapter
-						     (adapter));
-						zfcp_erp_adapter_reopen_internal(adapter, 0);
-					}
-				}
 			}
 		} else {
 			debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq");
@@ -1122,12 +1485,36 @@ zfcp_erp_strategy(struct zfcp_erp_action
 		goto unlock;
 	case ZFCP_ERP_NOMEM:
 		/* no memory to continue immediately, let it sleep */
+		if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
+			++adapter->erp_low_mem_count;
+			erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
+		}
+		/* This condition is true if there is no memory available
+		   for any erp_action on this adapter. This implies that there
+		   are no elements in the memory pool(s) left for erp_actions.
+		   This might happen if an erp_action that used a memory pool
+		   element was timed out.
+		 */
+		if (adapter->erp_total_count == adapter->erp_low_mem_count) {
+			debug_text_event(adapter->erp_dbf, 3, "a_st_lowmem");
+			ZFCP_LOG_NORMAL
+				("error: Out of memory. No mempool elements "
+				 "available. Restarting IO on the adapter %s "
+				 "to free mempool.\n",
+				 zfcp_get_busid_by_adapter(adapter));
+			zfcp_erp_adapter_reopen_internal(adapter, 0);
+		} else {
 		debug_text_event(adapter->erp_dbf, 2, "a_st_memw");
 		retval = zfcp_erp_strategy_memwait(erp_action);
-		/* fall through, waiting for memory means action continues */
+		}
+		goto unlock;
 	case ZFCP_ERP_CONTINUES:
 		/* leave since this action runs asynchronously */
 		debug_text_event(adapter->erp_dbf, 6, "a_st_cont");
+		if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
+			--adapter->erp_low_mem_count;
+			erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
+		}
 		goto unlock;
 	}
 	/* ok, finished action (whatever its result is) */
@@ -1531,16 +1918,24 @@ zfcp_erp_strategy_check_unit(struct zfcp
 	debug_event(unit->port->adapter->erp_dbf, 5, &unit->fcp_lun,
 		    sizeof (fcp_lun_t));
 
-	if (result == ZFCP_ERP_SUCCEEDED) {
+	switch (result) {
+	case ZFCP_ERP_SUCCEEDED :
 		atomic_set(&unit->erp_counter, 0);
 		zfcp_erp_unit_unblock(unit);
-	} else {
-		/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
+		break;
+	case ZFCP_ERP_FAILED :
 		atomic_inc(&unit->erp_counter);
-		if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
+		if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS)
 			zfcp_erp_unit_failed(unit);
-			result = ZFCP_ERP_EXIT;
-		}
+		break;
+	case ZFCP_ERP_EXIT :
+		/* nothing */
+		break;
+	}
+
+	if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) {
+		zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */
+		result = ZFCP_ERP_EXIT;
 	}
 
 	return result;
@@ -1559,16 +1954,24 @@ zfcp_erp_strategy_check_port(struct zfcp
 	debug_text_event(port->adapter->erp_dbf, 5, "p_stct");
 	debug_event(port->adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
 
-	if (result == ZFCP_ERP_SUCCEEDED) {
+	switch (result) {
+	case ZFCP_ERP_SUCCEEDED :
 		atomic_set(&port->erp_counter, 0);
 		zfcp_erp_port_unblock(port);
-	} else {
-		/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
+		break;
+	case ZFCP_ERP_FAILED :
 		atomic_inc(&port->erp_counter);
-		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
+		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
+		break;
+	case ZFCP_ERP_EXIT :
+		/* nothing */
+		break;
+	}
+
+	if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
+		zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */
+		result = ZFCP_ERP_EXIT;
 			zfcp_erp_port_failed(port);
-			result = ZFCP_ERP_EXIT;
-		}
 	}
 
 	return result;
@@ -1586,16 +1989,24 @@ zfcp_erp_strategy_check_adapter(struct z
 {
 	debug_text_event(adapter->erp_dbf, 5, "a_stct");
 
-	if (result == ZFCP_ERP_SUCCEEDED) {
+	switch (result) {
+	case ZFCP_ERP_SUCCEEDED :
 		atomic_set(&adapter->erp_counter, 0);
 		zfcp_erp_adapter_unblock(adapter);
-	} else {
-		/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
+		break;
+	case ZFCP_ERP_FAILED :
 		atomic_inc(&adapter->erp_counter);
-		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
+		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS)
 			zfcp_erp_adapter_failed(adapter);
-			result = ZFCP_ERP_EXIT;
-		}
+		break;
+	case ZFCP_ERP_EXIT :
+		/* nothing */
+		break;
+	}
+
+	if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) {
+		zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */
+		result = ZFCP_ERP_EXIT;
 	}
 
 	return result;
@@ -1999,10 +2410,10 @@ zfcp_erp_adapter_strategy_generic(struct
 int
 zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
 {
-	int retval = 0;
-	struct zfcp_adapter *adapter = erp_action->adapter;
+	int retval;
 	int i;
-	volatile struct qdio_buffer_element *buffere;
+	volatile struct qdio_buffer_element *sbale;
+	struct zfcp_adapter *adapter = erp_action->adapter;
 	int retval_cleanup = 0;
 
 	if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
@@ -2034,10 +2445,10 @@ zfcp_erp_adapter_strategy_open_qdio(stru
 	 * put buffers into response queue,
 	 */
 	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
-		buffere = &(adapter->response_queue.buffer[i]->element[0]);
-		buffere->length = 0;
-		buffere->flags = SBAL_FLAGS_LAST_ENTRY;
-		buffere->addr = 0;
+		sbale = &(adapter->response_queue.buffer[i]->element[0]);
+		sbale->length = 0;
+		sbale->flags = SBAL_FLAGS_LAST_ENTRY;
+		sbale->addr = 0;
 	}
 
 	ZFCP_LOG_TRACE("Calling do QDIO busid=%s, flags=0x%x, queue_no=%i, "
@@ -2591,7 +3002,7 @@ zfcp_erp_port_strategy_open_common(struc
 		if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN |
 				      ZFCP_STATUS_PORT_DID_DID),
 				     &port->status)) {
-			ZFCP_LOG_DEBUG("port wwpn=0x%Lx is open ", port->wwpn);
+			ZFCP_LOG_DEBUG("port wwpn=0x%Lx is open\n", port->wwpn);
 			retval = ZFCP_ERP_SUCCEEDED;
 		} else {
 			ZFCP_LOG_DEBUG("failed to open port wwpn=0x%Lx\n",
@@ -2845,7 +3256,7 @@ zfcp_erp_port_strategy_open_common_looku
 	struct zfcp_port *port = erp_action->port;
 
 	zfcp_erp_timeout_init(erp_action);
-	retval = zfcp_nameserver_request(erp_action);
+	retval = zfcp_ns_gid_pn_request(erp_action);
 	if (retval == -ENOMEM) {
 		debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
 		debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
@@ -3087,6 +3498,10 @@ zfcp_erp_action_enqueue(int action,
 	 * efficient.
 	 */
 
+	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP,
+			      &adapter->status))
+		goto out;
+
 	debug_event(adapter->erp_dbf, 4, &action, sizeof (int));
 	/* check whether we really need this */
 	switch (action) {
@@ -3222,6 +3637,8 @@ zfcp_erp_action_enqueue(int action,
 	erp_action->action = action;
 	erp_action->status = status;
 
+	++adapter->erp_total_count;
+
 	/* finally put it into 'ready' queue and kick erp thread */
 	list_add(&erp_action->list, &adapter->erp_ready_head);
 	up(&adapter->erp_ready_sem);
@@ -3243,6 +3660,12 @@ zfcp_erp_action_dequeue(struct zfcp_erp_
 	int retval = 0;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
+	--adapter->erp_total_count;
+	if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
+		--adapter->erp_low_mem_count;
+		erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
+	}
+
 	debug_text_event(adapter->erp_dbf, 4, "a_actdeq");
 	debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int));
 	list_del(&erp_action->list);
@@ -3404,4 +3827,3 @@ zfcp_erp_action_to_ready(struct zfcp_erp
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_ext.h~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_ext.h
--- 25/drivers/s390/scsi/zfcp_ext.h~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_ext.h	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  * 
  * FCP adapter driver for IBM eServer zSeries 
  * 
- * Copyright 2002 IBM Corporation 
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
- *            Aron Zeh <arzeh@de.ibm.com> 
- *            Wolfgang Taphorn <taphorn@de.ibm.com> 
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com> 
  *            Heiko Carstens <heiko.carstens@de.ibm.com> 
  * 
@@ -30,7 +31,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.38 $"
+#define ZFCP_EXT_REVISION "$Revision: 1.45 $"
 
 #include "zfcp_def.h"
 
@@ -46,7 +47,6 @@ extern void zfcp_sysfs_port_remove_files
 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 *);
 
 /**************************** CONFIGURATION  *********************************/
@@ -65,7 +65,6 @@ extern void   zfcp_unit_dequeue(struct z
 extern int  zfcp_ccw_register(void);
 extern void zfcp_ccw_unregister(void);
 
-extern int  zfcp_initialize_with_0copy(struct zfcp_adapter *);
 extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int);
 extern int  zfcp_qdio_allocate(struct zfcp_adapter *);
 extern int  zfcp_qdio_allocate_queues(struct zfcp_adapter *);
@@ -74,6 +73,16 @@ extern int  zfcp_qdio_determine_pci(stru
 				    struct zfcp_fsf_req *);
 extern int  zfcp_qdio_reqid_check(struct zfcp_adapter *, void *);
 
+extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req
+	(struct zfcp_fsf_req *, int, int);
+extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr
+	(struct zfcp_fsf_req *);
+extern int zfcp_qdio_sbals_from_sg
+	(struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int, int);
+extern int zfcp_qdio_sbals_from_scsicmnd
+	(struct zfcp_fsf_req *, unsigned long, struct scsi_cmnd *);
+
+
 /******************************** FSF ****************************************/
 extern int  zfcp_fsf_open_port(struct zfcp_erp_action *);
 extern int  zfcp_fsf_close_port(struct zfcp_erp_action *);
@@ -83,17 +92,20 @@ extern int  zfcp_fsf_open_unit(struct zf
 extern int  zfcp_fsf_close_unit(struct zfcp_erp_action *);
 
 extern int  zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
+extern int  zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
+				  u32, u32, struct zfcp_sg_list *);
 extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long);
 extern int  zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
 extern int  zfcp_fsf_status_read(struct zfcp_adapter *, int);
-extern int  zfcp_fsf_req_create(struct zfcp_adapter *,u32, unsigned long *,
-				int, struct zfcp_fsf_req **);
-extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
-extern int  zfcp_fsf_send_generic(struct zfcp_fsf_req *, unsigned char,
-				  unsigned long *, struct timer_list *);
+extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
+			       unsigned long *, struct zfcp_fsf_req **);
+extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
+			    struct zfcp_erp_action *);
+extern int zfcp_fsf_send_els(struct zfcp_send_els *);
 extern int  zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *);
 extern int  zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
-					   struct zfcp_unit *, Scsi_Cmnd *,
+					   struct zfcp_unit *,
+					   struct scsi_cmnd *,
 					   int);
 extern int  zfcp_fsf_req_complete(struct zfcp_fsf_req *);
 extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *);
@@ -105,15 +117,11 @@ extern struct zfcp_fsf_req *zfcp_fsf_abo
 
 /******************************** FCP ****************************************/
 extern int  zfcp_nameserver_enqueue(struct zfcp_adapter *);
-extern int  zfcp_nameserver_request(struct zfcp_erp_action *);
-extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *);
+extern int  zfcp_ns_gid_pn_request(struct zfcp_erp_action *);
 
 /******************************* SCSI ****************************************/
 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 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);
 extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
 extern void set_host_byte(u32 *, char);
@@ -122,6 +130,11 @@ extern char *zfcp_get_fcp_sns_info_ptr(s
 extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *);
 extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
 
+extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *unit,
+				   struct scsi_cmnd *scsi_cmnd);
+extern int zfcp_scsi_command_sync(struct zfcp_unit *unit,
+				  struct scsi_cmnd *scsi_cmnd);
+
 /******************************** ERP ****************************************/
 extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int);
 extern int  zfcp_erp_adapter_reopen(struct zfcp_adapter *, int);
@@ -147,10 +160,12 @@ extern int  zfcp_erp_thread_kill(struct 
 extern int  zfcp_erp_wait(struct zfcp_adapter *);
 extern void zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *);
 
+extern int  zfcp_test_link(struct zfcp_port *);
+
 /******************************** AUX ****************************************/
 extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *,
 				   void *, int);
-extern void zfcp_cmd_dbf_event_scsi(const char *, Scsi_Cmnd *);
+extern void zfcp_cmd_dbf_event_scsi(const char *, struct scsi_cmnd *);
 extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *,
 				  struct fsf_status_read_buffer *, int);
 #ifdef ZFCP_STAT_REQSIZES
diff -puN drivers/s390/scsi/zfcp_fsf.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_fsf.c
--- 25/drivers/s390/scsi/zfcp_fsf.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_fsf.c	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  *
  * FCP adapter driver for IBM eServer zSeries
  *
- * Copyright 2002 IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com>
- *            Aron Zeh <arzeh@de.ibm.com>
- *            Wolfgang Taphorn <taphorn@de.ibm.com>
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com>
  *            Heiko Carstens <heiko.carstens@de.ibm.com>
  *
@@ -28,7 +29,7 @@
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_FSF_C_REVISION "$Revision: 1.16 $"
+#define ZFCP_FSF_C_REVISION "$Revision: 1.29 $"
 
 #include "zfcp_ext.h"
 
@@ -43,18 +44,22 @@ static int zfcp_fsf_send_fcp_command_tas
 static int zfcp_fsf_send_fcp_command_task_management_handler(
 	struct zfcp_fsf_req *);
 static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_generic_handler(struct zfcp_fsf_req *);
 static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
+static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
+static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
+static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
 static inline int zfcp_fsf_req_create_sbal_check(
 	unsigned long *, struct zfcp_qdio_queue *, int);
-static struct zfcp_fsf_req *zfcp_fsf_req_get(int, mempool_t *);
-static struct zfcp_fsf_req *zfcp_fsf_req_alloc(struct zfcp_adapter *, u32, int);
+static inline int zfcp_use_one_sbal(
+	struct scatterlist *, int, struct scatterlist *, int);
+static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
 static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);
 static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
 static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
 static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
 static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
 static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);
+static void zfcp_fsf_req_free(struct zfcp_fsf_req *);
 
 /* association between FSF command and FSF QTCB type */
 static u32 fsf_qtcb_type[] = {
@@ -67,7 +72,10 @@ static u32 fsf_qtcb_type[] = {
 	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,
 	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,
 	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,
-	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND
+	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
+	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,
+	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
+	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
 };
 
 /****************************************************************/
@@ -75,7 +83,6 @@ static u32 fsf_qtcb_type[] = {
 /****************************************************************/
 
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF
-#define ZFCP_LOG_AREA_PREFIX		ZFCP_LOG_AREA_PREFIX_FSF
 
 /*
  * function:	zfcp_fsf_req_alloc
@@ -91,93 +98,38 @@ static u32 fsf_qtcb_type[] = {
  *
  */
 static struct zfcp_fsf_req *
-zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
+zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
 {
+	size_t size;
+	void *ptr;
 	struct zfcp_fsf_req *fsf_req = NULL;
 
-	switch (fsf_cmd) {
+	if (req_flags & ZFCP_REQ_NO_QTCB)
+		size = sizeof(struct zfcp_fsf_req);
+	else
+		size = sizeof(struct zfcp_fsf_req_pool_element);
 
-	case FSF_QTCB_FCP_CMND:
-	case FSF_QTCB_ABORT_FCP_CMND:
-		fsf_req = zfcp_fsf_req_get(kmalloc_flags,
-					   adapter->pool.fcp_command_fsf);
-		if (unlikely(fsf_req &&
-		             (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))) {
-			/*
-			 * watch low mem buffer
-			 * Note: If the command is reset or aborted, two
-			 * timeouts (this and the SCSI ER one) will be started
-			 * for the command. There is no problem however as
-			 * the first expired timer will call adapter_reopen
-			 * which will delete the other 
-			 */
-			adapter->pool.fcp_command_fsf_timer.expires =
-			    jiffies + ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT;
-			add_timer(&adapter->pool.fcp_command_fsf_timer);
-		}
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 5, "fsfa_fcp");
-		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;
+	if (likely(pool != NULL))
+		ptr = mempool_alloc(pool, GFP_ATOMIC);
+	else
+		ptr = kmalloc(size, GFP_ATOMIC);
 
-	case FSF_QTCB_OPEN_PORT_WITH_DID:
-	case FSF_QTCB_OPEN_LUN:
-	case FSF_QTCB_CLOSE_LUN:
-	case FSF_QTCB_CLOSE_PORT:
-	case FSF_QTCB_CLOSE_PHYSICAL_PORT:
-	case FSF_QTCB_SEND_ELS:
-	case FSF_QTCB_EXCHANGE_CONFIG_DATA:
-	case FSF_QTCB_SEND_GENERIC:
-		fsf_req =
-		    zfcp_fsf_req_get(kmalloc_flags, adapter->pool.erp_fsf);
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 5, "fsfa_erp");
-		if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))
-			debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
-#endif				/* ZFCP_DEBUG_REQUESTS */
-		break;
+	if (unlikely(NULL == ptr))
+		goto out;
 
-	case FSF_QTCB_UNSOLICITED_STATUS:
-		fsf_req =
-		    mempool_alloc(adapter->pool.status_read_fsf, GFP_ATOMIC);
-		if (fsf_req) {
-			memset(fsf_req, 0, sizeof (struct zfcp_fsf_req));
-			fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
-		} else
-			ZFCP_LOG_NORMAL("bug: could not find free fsf_req\n");
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 5, "fsfa_sr");
-		debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
-#endif				/* ZFCP_DEBUG_REQUESTS */
-		break;
+	memset(ptr, 0, size);
 
-	default:
-		ZFCP_LOG_NORMAL("bug: An attempt to send an unsupported "
-				"command has been detected. "
-				"(debug info 0x%x)\n", fsf_cmd);
-	}			//switch(fsf_cmd)
-
-	if (unlikely(!fsf_req)) {
-		ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF "
-			       "request structure failed\n");
+	if (req_flags & ZFCP_REQ_NO_QTCB) {
+		fsf_req = (struct zfcp_fsf_req *) ptr;
 	} else {
-		ZFCP_LOG_TRACE("FSF request allocated at 0x%lx, "
-			       "adapter 0x%lx (%s)\n",
-			       (unsigned long) fsf_req,
-			       (unsigned long) adapter,
-			       zfcp_get_busid_by_adapter(adapter));
+		fsf_req = &((struct zfcp_fsf_req_pool_element *) ptr)->fsf_req;
+		fsf_req->qtcb =
+			&((struct zfcp_fsf_req_pool_element *) ptr)->qtcb;
 	}
 
-#ifdef ZFCP_DEBUG_REQUESTS
-	debug_event(adapter->req_dbf, 5, &fsf_req, sizeof (unsigned long));
-	if (likely(fsf_req->qtcb))
-		debug_event(adapter->req_dbf, 5, &fsf_req->qtcb,
-			    sizeof (unsigned long));
-#endif				/* ZFCP_DEBUG_REQUESTS */
+	fsf_req->pool = pool;
 
+ out:
 	return fsf_req;
 }
 
@@ -191,40 +143,13 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *
  *
  * locks:       none
  */
-void
+static void
 zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
 {
-	struct zfcp_adapter *adapter = fsf_req->adapter;
-
-	switch (fsf_req->fsf_command) {
-
-	case FSF_QTCB_FCP_CMND:
-	case FSF_QTCB_ABORT_FCP_CMND:
-		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
-			kfree(fsf_req);
-		break;
-
-	case FSF_QTCB_OPEN_PORT_WITH_DID:
-	case FSF_QTCB_OPEN_LUN:
-	case FSF_QTCB_CLOSE_LUN:
-	case FSF_QTCB_CLOSE_PORT:
-	case FSF_QTCB_CLOSE_PHYSICAL_PORT:
-	case FSF_QTCB_SEND_ELS:
-	case FSF_QTCB_EXCHANGE_CONFIG_DATA:
-	case FSF_QTCB_SEND_GENERIC:
-		if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)
-			mempool_free(fsf_req, adapter->pool.erp_fsf);
+	if (likely(fsf_req->pool != NULL))
+		mempool_free(fsf_req, fsf_req->pool);
 		else
 			kfree(fsf_req);
-		break;
-
-	case FSF_QTCB_UNSOLICITED_STATUS:
-		mempool_free(fsf_req, adapter->pool.status_read_fsf);
-		break;
-	}
 }
 
 /*
@@ -386,23 +311,24 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf
 	/* log additional information provided by FSF (if any) */
 	if (unlikely(fsf_req->qtcb->header.log_length)) {
 		/* do not trust them ;-) */
-		if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) {
+		if (fsf_req->qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
 			ZFCP_LOG_NORMAL
 			    ("bug: ULP (FSF logging) log data starts "
 			     "beyond end of packet header. Ignored. "
 			     "(start=%i, size=%li)\n",
-			     fsf_req->qtcb->header.log_start, ZFCP_QTCB_SIZE);
+			     fsf_req->qtcb->header.log_start,
+			     sizeof(struct fsf_qtcb));
 			goto forget_log;
 		}
 		if ((fsf_req->qtcb->header.log_start +
 		     fsf_req->qtcb->header.log_length)
-		    > ZFCP_QTCB_SIZE) {
+		    > sizeof(struct fsf_qtcb)) {
 			ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
 					"beyond end of packet header. Ignored. "
 					"(start=%i, length=%i, size=%li)\n",
 					fsf_req->qtcb->header.log_start,
 					fsf_req->qtcb->header.log_length,
-					ZFCP_QTCB_SIZE);
+					sizeof(struct fsf_qtcb));
 			goto forget_log;
 		}
 		ZFCP_LOG_TRACE("ULP log data: \n");
@@ -667,7 +593,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf
 			      (char *) (((unsigned long) fsf_req) & 0xFFFFFF00),
 			      sizeof (struct zfcp_fsf_req));
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) fsf_req->qtcb,
-			      ZFCP_QTCB_SIZE);
+			      sizeof(struct fsf_qtcb));
 		debug_text_event(adapter->erp_dbf, 0, "prot_inval:");
 		debug_exception(adapter->erp_dbf, 0,
 				&fsf_req->qtcb->prefix.prot_status,
@@ -852,7 +778,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_re
 			       (unsigned long) fsf_req,
 			       (unsigned long) (fsf_req->qtcb));
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
-			      (char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
+			      (char *) fsf_req->qtcb, sizeof(struct fsf_qtcb));
 	}
 
 	switch (fsf_req->fsf_command) {
@@ -869,44 +795,52 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_re
 
 	case FSF_QTCB_SEND_GENERIC:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_GENERIC\n");
-		zfcp_fsf_send_generic_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
+		zfcp_fsf_send_ct_handler(fsf_req);
 		break;
 
 	case FSF_QTCB_OPEN_PORT_WITH_DID:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_OPEN_PORT_WITH_DID\n");
 		zfcp_fsf_open_port_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
 		break;
 
 	case FSF_QTCB_OPEN_LUN:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_OPEN_LUN\n");
 		zfcp_fsf_open_unit_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
 		break;
 
 	case FSF_QTCB_CLOSE_LUN:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_CLOSE_LUN\n");
 		zfcp_fsf_close_unit_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
 		break;
 
 	case FSF_QTCB_CLOSE_PORT:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_CLOSE_PORT\n");
 		zfcp_fsf_close_port_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
 		break;
 
 	case FSF_QTCB_CLOSE_PHYSICAL_PORT:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_CLOSE_PHYSICAL_PORT\n");
 		zfcp_fsf_close_physical_port_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
 		break;
 
 	case FSF_QTCB_EXCHANGE_CONFIG_DATA:
 		ZFCP_LOG_FLAGS(2, "FSF_QTCB_EXCHANGE_CONFIG_DATA\n");
 		zfcp_fsf_exchange_config_data_handler(fsf_req);
-		zfcp_erp_fsf_req_handler(fsf_req);
+		break;
+
+	case FSF_QTCB_SEND_ELS :
+		ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_ELS\n");
+		zfcp_fsf_send_els_handler(fsf_req);
+		break;
+
+	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
+		ZFCP_LOG_FLAGS(2, "FSF_QTCB_DOWNLOAD_CONTROL_FILE\n");
+		zfcp_fsf_control_file_handler(fsf_req);
+		break;
+
+	case FSF_QTCB_UPLOAD_CONTROL_FILE:
+		ZFCP_LOG_FLAGS(2, "FSF_QTCB_UPLOAD_CONTROL_FILE\n");
+		zfcp_fsf_control_file_handler(fsf_req);
 		break;
 
 	default:
@@ -927,6 +861,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_re
 			     fsf_req->qtcb->header.fsf_command);
 	}
 
+        zfcp_erp_fsf_req_handler(fsf_req);
 	return retval;
 }
 
@@ -943,14 +878,14 @@ zfcp_fsf_status_read(struct zfcp_adapter
 	struct zfcp_fsf_req *fsf_req;
 	struct fsf_status_read_buffer *status_buffer;
 	unsigned long lock_flags;
-	volatile struct qdio_buffer_element *buffere;
-	struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
+	volatile struct qdio_buffer_element *sbale;
 	int retval = 0;
 
 	/* setup new FSF request */
-	retval = zfcp_fsf_req_create(adapter,
-				     FSF_QTCB_UNSOLICITED_STATUS,
-				     &lock_flags, req_flags, &fsf_req);
+	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
+				     req_flags | ZFCP_REQ_NO_QTCB,
+				     adapter->pool.fsf_req_status_read,
+				     &lock_flags, &fsf_req);
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
 			      "unsolicited status buffer for "
@@ -959,8 +894,13 @@ zfcp_fsf_status_read(struct zfcp_adapter
 		goto failed_req_create;
 	}
 
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
+        sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
+        fsf_req->sbale_curr = 2;
+
 	status_buffer =
-	    mempool_alloc(adapter->pool.status_read_buf, GFP_ATOMIC);
+		mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
 	if (!status_buffer) {
 		ZFCP_LOG_NORMAL("bug: could not get some buffer\n");
 		goto failed_buf;
@@ -969,9 +909,9 @@ zfcp_fsf_status_read(struct zfcp_adapter
 	fsf_req->data.status_read.buffer = status_buffer;
 
 	/* insert pointer to respective buffer */
-	buffere = req_queue->buffer[fsf_req->sbal_index]->element;
-	buffere[2].addr = (void *) status_buffer;
-	buffere[2].length = sizeof (struct fsf_status_read_buffer);
+	sbale = zfcp_qdio_sbale_curr(fsf_req);
+	sbale->addr = (void *) status_buffer;
+	sbale->length = sizeof(struct fsf_status_read_buffer);
 
 	/* start QDIO request for this FSF request */
 	retval = zfcp_fsf_req_send(fsf_req, NULL);
@@ -990,7 +930,7 @@ zfcp_fsf_status_read(struct zfcp_adapter
 	goto out;
 
  failed_req_send:
-	mempool_free(status_buffer, adapter->pool.status_read_buf);
+	mempool_free(status_buffer, adapter->pool.data_status_read);
 
  failed_buf:
 	zfcp_fsf_req_free(fsf_req);
@@ -1072,7 +1012,7 @@ zfcp_fsf_status_read_handler(struct zfcp
 	    fsf_req->data.status_read.buffer;
 
 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
-		mempool_free(status_buffer, adapter->pool.status_read_buf);
+		mempool_free(status_buffer, adapter->pool.data_status_read);
 		zfcp_fsf_req_cleanup(fsf_req);
 		goto out;
 	}
@@ -1104,6 +1044,7 @@ zfcp_fsf_status_read_handler(struct zfcp
 
 	case FSF_STATUS_READ_LINK_DOWN:
 		ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_LINK_DOWN\n");
+
 		/* Unneccessary, ignoring.... */
 		break;
 
@@ -1121,6 +1062,59 @@ zfcp_fsf_status_read_handler(struct zfcp
 		zfcp_erp_adapter_reopen(adapter,
 					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
 					| ZFCP_STATUS_COMMON_ERP_FAILED);
+
+		break;
+
+	case FSF_STATUS_READ_NOTIFICATION_LOST:
+		ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_NOTIFICATION_LOST\n");
+		debug_text_event(adapter->erp_dbf, 2, "unsol_not_lost:");
+		switch (status_buffer->status_subtype) {
+		case FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED:
+			ZFCP_LOG_NORMAL(
+				"The unsolicited status information about "
+				"CFDC update on the adapter %s is lost "
+				"due to the lack of internal resources\n",
+				zfcp_get_busid_by_adapter(adapter));
+			break;
+		case FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED:
+			ZFCP_LOG_NORMAL(
+				"The unsolicited status information about "
+				"CFDC harden on the adapter %s is lost "
+				"due to the lack of internal resources\n",
+				zfcp_get_busid_by_adapter(adapter));
+			break;
+		}
+		break;
+
+	case FSF_STATUS_READ_CFDC_UPDATED:
+		ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_CFDC_UPDATED\n");
+		debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_update:");
+		ZFCP_LOG_NORMAL(
+			"CFDC has been updated on the adapter %s\n",
+			zfcp_get_busid_by_adapter(adapter));
+		break;
+
+	case FSF_STATUS_READ_CFDC_HARDENED:
+		ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_CFDC_HARDENED\n");
+		debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_harden:");
+		switch (status_buffer->status_subtype) {
+		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE:
+			ZFCP_LOG_NORMAL(
+				"CFDC of the adapter %s "
+				"has been saved on the SE\n",
+				zfcp_get_busid_by_adapter(adapter));
+			break;
+		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2:
+			ZFCP_LOG_NORMAL(
+				"CFDC of the adapter %s "
+				"has been copied to the secondary SE\n",
+				zfcp_get_busid_by_adapter(adapter));
+			break;
+		default:
+			ZFCP_LOG_NORMAL(
+				"CFDC of the adapter %s has been hardened\n",
+				zfcp_get_busid_by_adapter(adapter));
+		}
 		break;
 
 	default:
@@ -1138,7 +1132,7 @@ zfcp_fsf_status_read_handler(struct zfcp
 			      sizeof (struct fsf_status_read_buffer));
 		break;
 	}
-	mempool_free(status_buffer, adapter->pool.status_read_buf);
+	mempool_free(status_buffer, adapter->pool.data_status_read);
 	zfcp_fsf_req_cleanup(fsf_req);
 	/*
 	 * recycle buffer and start new request repeat until outbound
@@ -1192,13 +1186,15 @@ zfcp_fsf_abort_fcp_command(unsigned long
 			   struct zfcp_adapter *adapter,
 			   struct zfcp_unit *unit, int req_flags)
 {
-	struct zfcp_fsf_req *new_fsf_req = NULL;
-	int retval = 0;
+	volatile struct qdio_buffer_element *sbale;
 	unsigned long lock_flags;
+	struct zfcp_fsf_req *fsf_req = NULL;
+	int retval = 0;
 
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
-				     &lock_flags, req_flags, &new_fsf_req);
+				     req_flags, adapter->pool.fsf_req_abort,
+				     &lock_flags, &fsf_req);
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
 			      "abort command request on the device with "
@@ -1211,19 +1207,23 @@ zfcp_fsf_abort_fcp_command(unsigned long
 		goto out;
 	}
 
-	new_fsf_req->data.abort_fcp_command.unit = unit;
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+	fsf_req->data.abort_fcp_command.unit = unit;
 
 	/* set handles of unit and its parent port in QTCB */
-	new_fsf_req->qtcb->header.lun_handle = unit->handle;
-	new_fsf_req->qtcb->header.port_handle = unit->port->handle;
+	fsf_req->qtcb->header.lun_handle = unit->handle;
+	fsf_req->qtcb->header.port_handle = unit->port->handle;
 
 	/* set handle of request which should be aborted */
-	new_fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
+	fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
 
 	/* start QDIO request for this FSF request */
 
 	zfcp_fsf_start_scsi_er_timer(adapter);
-	retval = zfcp_fsf_req_send(new_fsf_req, NULL);
+	retval = zfcp_fsf_req_send(fsf_req, NULL);
 	if (retval) {
 		del_timer(&adapter->scsi_er_timer);
 		ZFCP_LOG_INFO("error: Could not send an abort command request "
@@ -1231,8 +1231,8 @@ zfcp_fsf_abort_fcp_command(unsigned long
 			      "port WWPN 0x%Lx and unit LUN 0x%Lx\n",
 			      zfcp_get_busid_by_adapter(adapter),
 			      unit->port->wwpn, unit->fcp_lun);
-		zfcp_fsf_req_free(new_fsf_req);
-		new_fsf_req = NULL;
+		zfcp_fsf_req_free(fsf_req);
+		fsf_req = NULL;
 		goto out;
 	}
 
@@ -1244,7 +1244,7 @@ zfcp_fsf_abort_fcp_command(unsigned long
 		       unit->fcp_lun, old_req_id);
  out:
 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
-	return new_fsf_req;
+	return fsf_req;
 }
 
 /*
@@ -1429,73 +1429,183 @@ zfcp_fsf_abort_fcp_command_handler(struc
 	return retval;
 }
 
-/*
- * function:    zfcp_fsf_send_generic
- *
- * purpose:	sends a FC request according to FC-GS-3
- *
- * returns:	address of initiated FSF request
- *		NULL - request could not be initiated 
+/**
+ * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
+ *	one SBALE
+ * Two scatter-gather lists are passed, one for the reqeust and one for the
+ * response.
+ */
+static inline int
+zfcp_use_one_sbal(struct scatterlist *req, int req_count,
+                  struct scatterlist *resp, int resp_count)
+{
+        return ((req_count == 1) &&
+		(resp_count == 1) &&
+                (((unsigned long) zfcp_sg_to_address(&req[0]) &
+		  PAGE_MASK) ==
+		 ((unsigned long) (zfcp_sg_to_address(&req[0]) +
+				   req[0].length - 1) & PAGE_MASK)) &&
+                (((unsigned long) zfcp_sg_to_address(&resp[0]) &
+		  PAGE_MASK) ==
+                 ((unsigned long) (zfcp_sg_to_address(&resp[0]) +
+				   resp[0].length - 1) & PAGE_MASK)));
+}
+
+/**
+ * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
+ * @ct: pointer to struct zfcp_send_ct which conatins all needed data for
+ *	the request
+ * @pool: pointer to memory pool, if non-null this pool is used to allocate
+ *	a struct zfcp_fsf_req
+ * @erp_action: pointer to erp_action, if non-null the Generic Service request
+ *	is sent within error recovery
  */
 int
-zfcp_fsf_send_generic(struct zfcp_fsf_req *fsf_req, unsigned char timeout,
-		      unsigned long *lock_flags, struct timer_list *timer)
+zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
+		 struct zfcp_erp_action *erp_action)
 {
-	int retval = 0;
-	struct qdio_buffer *buffer;
-	volatile struct qdio_buffer_element *buffer_element = NULL;
-	struct zfcp_port *port = fsf_req->data.send_generic.port;
-	struct zfcp_adapter *adapter = port->adapter;
-
-	/* put buffers to the 2 SBALEs after the QTCB */
-	buffer = (adapter->request_queue.buffer[fsf_req->sbal_index]);
-	buffer_element = &(buffer->element[2]);
-	buffer_element->addr = fsf_req->data.send_generic.outbuf;
-	buffer_element->length = fsf_req->data.send_generic.outbuf_length;
-	buffer_element++;
-	buffer_element->addr = fsf_req->data.send_generic.inbuf;
-	buffer_element->length = fsf_req->data.send_generic.inbuf_length;
-	buffer_element->flags |= SBAL_FLAGS_LAST_ENTRY;
+	volatile struct qdio_buffer_element *sbale;
+	struct zfcp_port *port;
+	struct zfcp_adapter *adapter;
+        struct zfcp_fsf_req *fsf_req;
+        unsigned long lock_flags;
+        int bytes;
+	int ret = 0;
+
+	port = ct->port;
+	adapter = port->adapter;
+
+	ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
+				  ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
+				  pool, &lock_flags, &fsf_req);
+	if (ret < 0) {
+                ZFCP_LOG_INFO("error: out of memory. Could not create CT "
+			      "request (FC-GS). (adapter: %s)\n",
+			      zfcp_get_busid_by_adapter(adapter));
+		goto failed_req;
+	}
+
+        if (erp_action != NULL) {
+                erp_action->fsf_req = fsf_req;
+                fsf_req->erp_action = erp_action;
+        }
+
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+        if (zfcp_use_one_sbal(ct->req, ct->req_count,
+                              ct->resp, ct->resp_count)){
+                /* both request buffer and response buffer
+                   fit into one sbale each */
+                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+                sbale[2].addr = zfcp_sg_to_address(&ct->req[0]);
+                sbale[2].length = ct->req[0].length;
+                sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
+                sbale[3].length = ct->resp[0].length;
+                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+        } else if (adapter->supported_features &
+                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
+                /* try to use chained SBALs */
+                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+                                                SBAL_FLAGS0_TYPE_WRITE_READ,
+                                                ct->req, ct->req_count,
+                                                ZFCP_MAX_SBALS_PER_CT_REQ);
+                if (bytes <= 0) {
+                        ZFCP_LOG_INFO("error: out of resources (outbuf). "
+                                      "Could not create CT request (FC-GS). "
+				      "(adapter: %s)\n",
+				      zfcp_get_busid_by_adapter(adapter));
+                        if (bytes == 0)
+                                ret = -ENOMEM;
+                        else
+                                ret = bytes;
+
+                        goto failed_send;
+                }
+                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
+                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+                                                SBAL_FLAGS0_TYPE_WRITE_READ,
+                                                ct->resp, ct->resp_count,
+                                                ZFCP_MAX_SBALS_PER_CT_REQ);
+                if (bytes <= 0) {
+                        ZFCP_LOG_INFO("error: out of resources (inbuf). "
+                                      "Could not create a CT request (FC-GS). "
+				      "(adapter: %s)\n",
+				      zfcp_get_busid_by_adapter(adapter));
+                        if (bytes == 0)
+                                ret = -ENOMEM;
+                        else
+                                ret = bytes;
+
+                        goto failed_send;
+                }
+                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
+        } else {
+                /* reject send generic request */
+		ZFCP_LOG_INFO(
+			"error: microcode does not support chained SBALs."
+                        "CT request (FC-GS) too big. (adapter: %s)\n",
+			zfcp_get_busid_by_adapter(adapter));
+                ret = -EOPNOTSUPP;
+                goto failed_send;
+        }
 
 	/* settings in QTCB */
 	fsf_req->qtcb->header.port_handle = port->handle;
 	fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
-	fsf_req->qtcb->bottom.support.timeout = timeout;
+	fsf_req->qtcb->bottom.support.timeout = ct->timeout;
+        fsf_req->data.send_ct = ct;
 
 	/* start QDIO request for this FSF request */
-	retval = zfcp_fsf_req_send(fsf_req, timer);
-	if (retval) {
-		ZFCP_LOG_DEBUG("error: Out of resources. could not send a "
-			       "generic services "
-			       "command via the adapter %s, port "
-			       "WWPN 0x%Lx\n",
+	ret = zfcp_fsf_req_send(fsf_req, ct->timer);
+	if (ret) {
+		ZFCP_LOG_DEBUG("error: out of resources. Could not send CT "
+			       "request (FC-GS). (adapter: %s, "
+			       "port WWPN 0x%Lx)\n",
 			       zfcp_get_busid_by_adapter(adapter), port->wwpn);
-		/*
-		 * fsf_req structure will be cleaned up by higher layer handler
-		 */
-		goto out;
+		goto failed_send;
 	}
 
-	ZFCP_LOG_DEBUG("Send Generic request initiated "
-		       "(adapter busido=%s, port d_id=0x%x)\n",
-		       zfcp_get_busid_by_adapter(adapter),
-		       (unsigned int) port->d_id);
+	ZFCP_LOG_DEBUG("CT request initiated. (adapter: %s, port WWPN 0x%Lx)\n",
+		       zfcp_get_busid_by_adapter(adapter), port->wwpn);
+	goto out;
+
+ failed_send:
+	zfcp_fsf_req_free(fsf_req);
+        if (erp_action != NULL) {
+                erp_action->fsf_req = NULL;
+        }
+ failed_req:
  out:
-	return retval;
+        write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+				lock_flags);
+	return ret;
 }
 
-/*
- * function:    zfcp_fsf_send_generic_handler
- *
- * purpose:	is called for finished Send Generic request
- *
- * returns:	
+/**
+ * zfcp_fsf_send_ct_handler - handler for Generic Service requests
+ * @fsf_req: pointer to struct zfcp_fsf_req
+ *
+ * Data specific for the Generic Service request is passed by
+ * fsf_req->data.send_ct
+ * Usually a specific handler for the request is called via
+ * fsf_req->data.send_ct->handler at end of this function.
  */
 static int
-zfcp_fsf_send_generic_handler(struct zfcp_fsf_req *fsf_req)
+zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 {
+	struct zfcp_port *port;
+	struct zfcp_adapter *adapter;
+	struct zfcp_send_ct *send_ct;
+	struct fsf_qtcb_header *header;
+	struct fsf_qtcb_bottom_support *bottom;
 	int retval = -EINVAL;
-	struct zfcp_port *port = fsf_req->data.send_generic.port;
+	u16 subtable, rule, counter;
+
+	adapter = fsf_req->adapter;
+	send_ct = fsf_req->data.send_ct;
+	port = send_ct->port;
+	header = &fsf_req->qtcb->header;
+	bottom = &fsf_req->qtcb->bottom.support;
 
 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
 		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
@@ -1503,184 +1613,518 @@ zfcp_fsf_send_generic_handler(struct zfc
 	}
 
 	/* evaluate FSF status in QTCB */
-	switch (fsf_req->qtcb->header.fsf_status) {
+	switch (header->fsf_status) {
 
-	case FSF_PORT_HANDLE_NOT_VALID:
-		ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
-		ZFCP_LOG_DEBUG("Temporary port identifier (handle) 0x%x "
-			       "for the port with WWPN 0x%Lx connected to "
-			       "the adapter %s is "
-			       "not valid. This may happen occasionally.\n",
-			       port->handle,
-			       port->wwpn, zfcp_get_busid_by_port(port));
-		ZFCP_LOG_INFO("status qualifier:\n");
-		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
-			      sizeof (union fsf_status_qual));
-		debug_text_event(fsf_req->adapter->erp_dbf, 1,
-				 "fsf_s_phandle_nv");
-		zfcp_erp_adapter_reopen(port->adapter, 0);
-		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+        case FSF_GOOD :
+                ZFCP_LOG_FLAGS(2,"FSF_GOOD\n");
+                retval = 0;
 		break;
 
-	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
-		ZFCP_LOG_FLAGS(0, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n");
-		if (fsf_req->adapter->fc_service_class <= 3) {
-			ZFCP_LOG_NORMAL("error: The adapter %s does "
+        case FSF_SERVICE_CLASS_NOT_SUPPORTED :
+		ZFCP_LOG_FLAGS(2, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n");
+		if (adapter->fc_service_class <= 3) {
+			ZFCP_LOG_INFO("error: The adapter %s does "
 					"not support fibre-channel class %d.\n",
 					zfcp_get_busid_by_port(port),
-					fsf_req->adapter->fc_service_class);
+				      adapter->fc_service_class);
 		} else {
-			ZFCP_LOG_NORMAL
-			    ("bug: The fibre channel class at the adapter "
-			     "%s is invalid. " "(debug info %d)\n",
+			ZFCP_LOG_INFO("bug: The fibre channel class at the "
+				      "adapter %s is invalid. "
+				      "(debug info %d)\n",
 			     zfcp_get_busid_by_port(port),
-			     fsf_req->adapter->fc_service_class);
+				      adapter->fc_service_class);
 		}
 		/* stop operation for this adapter */
-		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
-				     "fsf_s_class_nsup");
+		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
 		zfcp_erp_adapter_shutdown(port->adapter, 0);
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
-	case FSF_GENERIC_COMMAND_REJECTED:
-		ZFCP_LOG_FLAGS(1, "FSF_GENERIC_COMMAND_REJECTED\n");
+        case FSF_ADAPTER_STATUS_AVAILABLE :
+                ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
+                switch (header->fsf_status_qual.word[0]){
+                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
+			ZFCP_LOG_FLAGS(2,"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
+			/* reopening link to port */
+			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
+			zfcp_test_link(port);
+			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+			break;
+                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
+			ZFCP_LOG_FLAGS(2,"FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n");
+			/* ERP strategy will escalate */
+			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
+			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+			break;
+                default:
+			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x "
+				      "arrived.\n",
+				      header->fsf_status_qual.word[0]);
+			break;
+                }
+                break;
+
+	case FSF_ACCESS_DENIED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+		ZFCP_LOG_NORMAL("Access denied, cannot send generic command "
+				"to a port with WWPN 0x%Lx connected "
+				"to the adapter %s\n", port->wwpn,
+				zfcp_get_busid_by_port(port));
+		counter = 0;
+		do {
+			subtable = header->fsf_status_qual.halfword[counter++];
+			rule = header->fsf_status_qual.halfword[counter++];
+			switch (subtable) {
+			case FSF_SQ_CFDC_SUBTABLE_OS:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+			case FSF_SQ_CFDC_SUBTABLE_LUN:
+       				ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+					zfcp_act_subtable_type[subtable], rule);
+				break;
+			}
+		} while (counter < 4);
+		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
+        case FSF_GENERIC_COMMAND_REJECTED :
+		ZFCP_LOG_FLAGS(2, "FSF_GENERIC_COMMAND_REJECTED\n");
 		ZFCP_LOG_INFO("warning: The port with WWPN 0x%Lx connected to "
-			      "the adapter %s is"
+			      "the adapter %s has "
 			      "rejected a generic services command.\n",
 			      port->wwpn, zfcp_get_busid_by_port(port));
 		ZFCP_LOG_INFO("status qualifier:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
-		debug_text_event(fsf_req->adapter->erp_dbf, 1,
-				 "fsf_s_gcom_rej");
+		debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej");
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
-	case FSF_REQUEST_BUF_NOT_VALID:
-		ZFCP_LOG_FLAGS(1, "FSF_REQUEST_BUF_NOT_VALID\n");
+        case FSF_PORT_HANDLE_NOT_VALID :
+		ZFCP_LOG_FLAGS(2, "FSF_PORT_HANDLE_NOT_VALID\n");
+		ZFCP_LOG_DEBUG("Temporary port identifier (handle) 0x%x "
+			       "for the port with WWPN 0x%Lx connected to "
+			       "the adapter %s is "
+			       "not valid. This may happen occasionally.\n",
+			       port->handle,
+			       port->wwpn, zfcp_get_busid_by_port(port));
+		ZFCP_LOG_INFO("status qualifier:\n");
+		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
+			      (char *) &header->fsf_status_qual,
+			      sizeof (union fsf_status_qual));
+		debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv");
+		zfcp_erp_adapter_reopen(port->adapter, 0);
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
+	case FSF_REQUEST_BUF_NOT_VALID :
+		ZFCP_LOG_FLAGS(2, "FSF_REQUEST_BUF_NOT_VALID\n");
 		ZFCP_LOG_NORMAL("error: The port with WWPN 0x%Lx connected to "
-				"the adapter %s is"
+				"the adapter %s has "
 				"rejected a generic services command "
 				"due to invalid request buffer.\n",
 				port->wwpn, zfcp_get_busid_by_port(port));
-		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_reqiv");
+		debug_text_event(adapter->erp_dbf, 1, "fsf_s_reqiv");
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
-	case FSF_RESPONSE_BUF_NOT_VALID:
-		ZFCP_LOG_FLAGS(1, "FSF_RESPONSE_BUF_NOT_VALID\n");
+	case FSF_RESPONSE_BUF_NOT_VALID :
+		ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_BUF_NOT_VALID\n");
 		ZFCP_LOG_NORMAL("error: The port with WWPN 0x%Lx connected to "
-				"the adapter %s is"
+				"the adapter %s has "
 				"rejected a generic services command "
 				"due to invalid response buffer.\n",
 				port->wwpn, zfcp_get_busid_by_port(port));
-		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_resiv");
+		debug_text_event(adapter->erp_dbf, 1, "fsf_s_resiv");
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
-	case FSF_PORT_BOXED:
+        case FSF_PORT_BOXED :
 		ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
 		ZFCP_LOG_DEBUG("The remote port "
 			       "with WWPN 0x%Lx on the adapter %s "
 			       "needs to be reopened\n",
 			       port->wwpn, zfcp_get_busid_by_port(port));
-		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
+		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
 		zfcp_erp_port_reopen(port, 0);
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
 		    | ZFCP_STATUS_FSFREQ_RETRY;
 		break;
 
-	case FSF_ADAPTER_STATUS_AVAILABLE:
-		ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
-		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
-		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
-			ZFCP_LOG_FLAGS(2,
-				       "FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
-			/* reopening link to port */
-			debug_text_event(fsf_req->adapter->erp_dbf, 1,
-					 "fsf_sq_ltest");
-			zfcp_erp_port_forced_reopen(port, 0);
-			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
-			break;
-		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
-			/* ERP strategy will escalate */
-			debug_text_event(fsf_req->adapter->erp_dbf, 1,
-					 "fsf_sq_ulp");
-			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
-			break;
-
-		default:
-			ZFCP_LOG_NORMAL
-			    ("bug: Wrong status qualifier 0x%x arrived.\n",
-			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
-			break;
-		}
-		break;
-
-	case FSF_GOOD:
-		ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
-		retval = 0;
-		break;
-
-	default:
+       default :
 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
-				"(debug info 0x%x)\n",
-				fsf_req->qtcb->header.fsf_status);
-		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval:");
-		debug_exception(fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status_qual.word[0],
-				sizeof (u32));
+				"(debug info 0x%x)\n", header->fsf_status);
+		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval:");
+		debug_exception(adapter->erp_dbf, 0,
+				&header->fsf_status_qual.word[0], sizeof (u32));
 		break;
 	}
- skip_fsfstatus:
-	/* callback */
-	(fsf_req->data.send_generic.handler)(fsf_req);
+
+skip_fsfstatus:
+	if (send_ct->handler != NULL) {
+		send_ct->handler(send_ct->handler_data);
+        }
+
 	return retval;
 }
 
-/*
- * function:
- *
- * purpose:
- *
- * returns:	address of initiated FSF request
- *		NULL - request could not be initiated
+/**
+ * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
+ * @els: pointer to struct zfcp_send_els which contains all needed data for
+ *	the command.
  */
 int
-zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
+zfcp_fsf_send_els(struct zfcp_send_els *els)
 {
-	int retval = 0;
+	volatile struct qdio_buffer_element *sbale;
+	struct zfcp_fsf_req *fsf_req;
+	struct zfcp_port *port;
+	struct zfcp_adapter *adapter;
 	unsigned long lock_flags;
+        int bytes;
+	int ret = 0;
 
-	/* setup new FSF request */
-	retval = zfcp_fsf_req_create(erp_action->adapter,
-				     FSF_QTCB_EXCHANGE_CONFIG_DATA,
-				     &lock_flags,
-				     ZFCP_REQ_AUTO_CLEANUP,
-				     &(erp_action->fsf_req));
-	if (retval < 0) {
-		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-			      "exchange configuration data request for"
-			      "the adapter %s.\n",
-			      zfcp_get_busid_by_adapter(erp_action->adapter));
-		goto out;
-	}
+	port = els->port;
+	adapter = port->adapter;
 
-	erp_action->fsf_req->erp_action = erp_action;
-	/* no information from us to adapter, set nothing */
+        ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
+				  ZFCP_WAIT_FOR_SBAL|ZFCP_REQ_AUTO_CLEANUP,
+				  NULL, &lock_flags, &fsf_req);
+	if (ret < 0) {
+                ZFCP_LOG_INFO("error: out of memory. Could not create ELS "
+			      "request. (adapter: %s, port did: 0x%06x)\n",
+                              zfcp_get_busid_by_adapter(adapter), port->d_id);
+                goto failed_req;
+	}
+
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+        if (zfcp_use_one_sbal(els->req, els->req_count,
+                              els->resp, els->resp_count)){
+                /* both request buffer and response buffer
+                   fit into one sbale each */
+                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+                sbale[2].addr = zfcp_sg_to_address(&els->req[0]);
+                sbale[2].length = els->req[0].length;
+                sbale[3].addr = zfcp_sg_to_address(&els->resp[0]);
+                sbale[3].length = els->resp[0].length;
+                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+        } else if (adapter->supported_features &
+                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
+                /* try to use chained SBALs */
+                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+                                                SBAL_FLAGS0_TYPE_WRITE_READ,
+                                                els->req, els->req_count,
+                                                ZFCP_MAX_SBALS_PER_ELS_REQ);
+                if (bytes <= 0) {
+                        ZFCP_LOG_INFO("error: out of resources (outbuf). "
+                                      "Could not create ELS request. "
+				      "(adapter: %s, port did: 0x%06x)\n",
+				      zfcp_get_busid_by_adapter(adapter),
+				      port->d_id);
+                        if (bytes == 0) {
+                                ret = -ENOMEM;
+                        } else {
+                                ret = bytes;
+                        }
+                        goto failed_send;
+                }
+                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
+                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
+                                                SBAL_FLAGS0_TYPE_WRITE_READ,
+                                                els->resp, els->resp_count,
+                                                ZFCP_MAX_SBALS_PER_ELS_REQ);
+                if (bytes <= 0) {
+                        ZFCP_LOG_INFO("error: out of resources (inbuf). "
+                                      "Could not create ELS request. "
+				      "(adapter: %s, port did: 0x%06x)\n",
+				      zfcp_get_busid_by_adapter(adapter),
+				      port->d_id);
+                        if (bytes == 0) {
+                                ret = -ENOMEM;
+                        } else {
+                                ret = bytes;
+                        }
+                        goto failed_send;
+                }
+                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
+        } else {
+                /* reject request */
+		ZFCP_LOG_INFO("error: microcode does not support chained SBALs."
+                              "ELS request too big. "
+			      "(adapter: %s, port did: 0x%06x)\n",
+			      zfcp_get_busid_by_adapter(adapter), port->d_id);
+                ret = -EOPNOTSUPP;
+                goto failed_send;
+        }
+
+	/* settings in QTCB */
+	fsf_req->qtcb->bottom.support.d_id = port->d_id;
+	fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
+	fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT;
+	fsf_req->data.send_els = els;
+
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
 
 	/* start QDIO request for this FSF request */
-	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
-	if (retval) {
-		ZFCP_LOG_INFO
-		    ("error: Could not send an exchange configuration data "
-		     "command on the adapter %s\n",
-		     zfcp_get_busid_by_adapter(erp_action->adapter));
-		zfcp_fsf_req_free(erp_action->fsf_req);
-		erp_action->fsf_req = NULL;
+	ret = zfcp_fsf_req_send(fsf_req, NULL);
+	if (ret) {
+		ZFCP_LOG_DEBUG("error: out of resources. Could not send ELS "
+                               "request. (adapter: %s, port WWPN 0x%Lx)\n",
+			       zfcp_get_busid_by_adapter(adapter), port->wwpn);
+		goto failed_send;
+	}
+
+	ZFCP_LOG_DEBUG("ELS request initiated (adapter: %s, port WWPN 0x%Lx)\n",
+		       zfcp_get_busid_by_adapter(adapter), port->wwpn);
+	goto out;
+
+ failed_send:
+	zfcp_fsf_req_free(fsf_req);
+
+ failed_req:
+ out:
+	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+				lock_flags);
+
+        return ret;
+}
+
+/**
+ * zfcp_fsf_send_els_handler - handler for ELS commands
+ * @fsf_req: pointer to struct zfcp_fsf_req
+ *
+ * Data specific for the ELS command is passed by
+ * fsf_req->data.send_els
+ * Usually a specific handler for the command is called via
+ * fsf_req->data.send_els->handler at end of this function.
+ */
+static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
+{
+	struct zfcp_adapter *adapter;
+	struct zfcp_port *port;
+	struct fsf_qtcb_header *header;
+	struct fsf_qtcb_bottom_support *bottom;
+	struct zfcp_send_els *send_els;
+	int retval = -EINVAL;
+	u16 subtable, rule, counter;
+
+	adapter = fsf_req->adapter;
+	send_els = fsf_req->data.send_els;
+	port = send_els->port;
+	header = &fsf_req->qtcb->header;
+	bottom = &fsf_req->qtcb->bottom.support;
+
+	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
+		goto skip_fsfstatus;
+
+	switch (header->fsf_status) {
+
+	case FSF_GOOD:
+		ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
+		retval = 0;
+		break;
+
+	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
+		ZFCP_LOG_FLAGS(2, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n");
+		if (adapter->fc_service_class <= 3) {
+			ZFCP_LOG_INFO("error: The adapter %s does "
+				      "not support fibre-channel class %d.\n",
+				      zfcp_get_busid_by_port(port),
+				      adapter->fc_service_class);
+		} else {
+			ZFCP_LOG_INFO("bug: The fibre channel class at the "
+				      "adapter %s is invalid. "
+				      "(debug info %d)\n",
+				      zfcp_get_busid_by_port(port),
+				      adapter->fc_service_class);
+		}
+		/* stop operation for this adapter */
+		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
+		zfcp_erp_adapter_shutdown(port->adapter, 0);
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
+	case FSF_ADAPTER_STATUS_AVAILABLE:
+		ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
+		switch (header->fsf_status_qual.word[0]){
+		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: {
+			ZFCP_LOG_FLAGS(2,"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
+			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
+			if (send_els->ls_code != ZFCP_LS_ADISC)
+				zfcp_test_link(port);
+			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+			break;
+		}
+		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
+			ZFCP_LOG_FLAGS(2,"FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n");
+			/* ERP strategy will escalate */
+			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
+			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+			break;
+		case FSF_SQ_RETRY_IF_POSSIBLE:
+			ZFCP_LOG_FLAGS(2, "FSF_SQ_RETRY_IF_POSSIBLE\n");
+			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry");
+			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+			break;
+		default:
+			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n",
+				      header->fsf_status_qual.word[0]);
+			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
+				(char*)header->fsf_status_qual.word, 16);
+		}
+		break;
+
+	case FSF_ELS_COMMAND_REJECTED:
+		ZFCP_LOG_FLAGS(2, "FSF_ELS_COMMAND_REJECTED\n");
+		ZFCP_LOG_INFO("The ELS command has been rejected because "
+			      "a command filter in the FCP channel prohibited "
+			      "sending of the ELS to the SAN "
+			      "(adapter: %s, wwpn=0x%016Lx)\n",
+			      zfcp_get_busid_by_port(port), port->wwpn);
+
+		break;
+
+	case FSF_PAYLOAD_SIZE_MISMATCH:
+		ZFCP_LOG_FLAGS(2, "FSF_PAYLOAD_SIZE_MISMATCH\n");
+		ZFCP_LOG_INFO(
+			"ELS request size and ELS response size must be either "
+			"both 0, or both greater than 0 "
+			"(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n",
+			zfcp_get_busid_by_port(port),
+			bottom->req_buf_length,
+			bottom->resp_buf_length);
+		break;
+
+	case FSF_REQUEST_SIZE_TOO_LARGE:
+		ZFCP_LOG_FLAGS(2, "FSF_REQUEST_SIZE_TOO_LARGE\n");
+		ZFCP_LOG_INFO(
+			"Length of the ELS request buffer, "
+			"specified in QTCB bottom, "
+			"exceeds the size of the buffers "
+			"that have been allocated for ELS request data "
+			"(adapter: %s, req_buf_length=%d)\n",
+			zfcp_get_busid_by_port(port),
+			bottom->req_buf_length);
+		break;
+
+	case FSF_RESPONSE_SIZE_TOO_LARGE:
+		ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_SIZE_TOO_LARGE\n");
+		ZFCP_LOG_INFO(
+			"Length of the ELS response buffer, "
+			"specified in QTCB bottom, "
+			"exceeds the size of the buffers "
+			"that have been allocated for ELS response data "
+			"(adapter: %s, resp_buf_length=%d)\n",
+			zfcp_get_busid_by_port(port),
+			bottom->resp_buf_length);
+		break;
+
+	case FSF_UNKNOWN_COMMAND:
+		ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n");
+		ZFCP_LOG_INFO(
+			"FSF command 0x%x is not supported by FCP adapter "
+			"(adapter: %s)\n", fsf_req->fsf_command,
+			zfcp_get_busid_by_port(port));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
+	case FSF_ACCESS_DENIED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+		ZFCP_LOG_NORMAL("Access denied, cannot send ELS "
+				"(adapter: %s, wwpn=0x%016Lx)\n",
+				zfcp_get_busid_by_port(port), port->wwpn);
+		counter = 0;
+		do {
+			subtable = header->fsf_status_qual.halfword[counter++];
+			rule = header->fsf_status_qual.halfword[counter++];
+			switch (subtable) {
+			case FSF_SQ_CFDC_SUBTABLE_OS:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+			case FSF_SQ_CFDC_SUBTABLE_LUN:
+				ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+					zfcp_act_subtable_type[subtable], rule);
+				break;
+			}
+		} while (counter < 4);
+		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
+	default:
+		ZFCP_LOG_NORMAL(
+			"bug: An unknown FSF Status was presented "
+			"(adapter: %s, fsf_status=0x%08x)\n",
+			zfcp_get_busid_by_port(port),
+			header->fsf_status);
+		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval");
+		debug_exception(adapter->erp_dbf, 0,
+			&header->fsf_status_qual.word[0], sizeof(u32));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+	}
+
+skip_fsfstatus:
+	send_els->status = retval;
+
+	if (send_els->handler != 0)
+		send_els->handler(send_els->handler_data);
+
+	kfree(send_els);
+
+	return retval;
+}
+
+/*
+ * function:
+ *
+ * purpose:
+ *
+ * returns:	address of initiated FSF request
+ *		NULL - request could not be initiated
+ */
+int
+zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
+{
+	volatile struct qdio_buffer_element *sbale;
+	unsigned long lock_flags;
+	int retval = 0;
+
+	/* setup new FSF request */
+	retval = zfcp_fsf_req_create(erp_action->adapter,
+				     FSF_QTCB_EXCHANGE_CONFIG_DATA,
+				     ZFCP_REQ_AUTO_CLEANUP,
+				     erp_action->adapter->pool.fsf_req_erp,
+				     &lock_flags, &(erp_action->fsf_req));
+	if (retval < 0) {
+		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+			      "exchange configuration data request for"
+			      "the adapter %s.\n",
+			      zfcp_get_busid_by_adapter(erp_action->adapter));
+		goto out;
+	}
+
+	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+                                    erp_action->fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+	erp_action->fsf_req->erp_action = erp_action;
+	erp_action->fsf_req->qtcb->bottom.config.feature_selection =
+		FSF_FEATURE_CFDC;
+
+	/* start QDIO request for this FSF request */
+	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+	if (retval) {
+		ZFCP_LOG_INFO
+		    ("error: Could not send an exchange configuration data "
+		     "command on the adapter %s\n",
+		     zfcp_get_busid_by_adapter(erp_action->adapter));
+		zfcp_fsf_req_free(erp_action->fsf_req);
+		erp_action->fsf_req = NULL;
 		goto out;
 	}
 
@@ -1702,7 +2146,8 @@ zfcp_fsf_exchange_config_data(struct zfc
  * returns:
  */
 static int
-zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) {
+zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
+{
 	int retval = -EIO;
 	struct fsf_qtcb_bottom_config *bottom;
 	struct zfcp_adapter *adapter = fsf_req->adapter;
@@ -1730,6 +2175,17 @@ zfcp_fsf_exchange_config_data_handler(st
 		adapter->fsf_lic_version = bottom->lic_version;
 		adapter->fc_topology = bottom->fc_topology;
 		adapter->fc_link_speed = bottom->fc_link_speed;
+                adapter->supported_features = bottom->supported_features;
+
+		if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
+			adapter->hardware_version = bottom->hardware_version;
+                        /* copy just first 17 bytes */
+                        memcpy(adapter->serial_number,
+                               bottom->serial_number, 17);
+                        EBCASC(adapter->serial_number,
+                               sizeof(adapter->serial_number));
+		}
+
 		ZFCP_LOG_INFO("The adapter %s reported "
 			      "the following characteristics:\n"
 			      "WWNN 0x%16.16Lx, "
@@ -1810,14 +2266,14 @@ zfcp_fsf_exchange_config_data_handler(st
 			zfcp_erp_adapter_shutdown(adapter, 0);
 			goto skip_fsfstatus;
 		}
-		if (bottom->max_qtcb_size < ZFCP_QTCB_SIZE) {
+		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
 			ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
 					"allowed by the adapter %s "
 					"is lower than the minimum "
 					"required by the driver (%ld bytes).\n",
 					bottom->max_qtcb_size,
 					zfcp_get_busid_by_adapter(adapter),
-					ZFCP_QTCB_SIZE);
+					sizeof(struct fsf_qtcb));
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "qtcb-size");
 			debug_event(fsf_req->adapter->erp_dbf, 0,
@@ -1828,13 +2284,14 @@ zfcp_fsf_exchange_config_data_handler(st
 		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
 				&adapter->status);
 		retval = 0;
+
 		break;
+
 	default:
 		/* retval is -EIO by default */
 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
 		debug_event(fsf_req->adapter->erp_dbf, 0,
 			    &fsf_req->qtcb->header.fsf_status, sizeof (u32));
-		zfcp_erp_adapter_shutdown(adapter, 0);
 	}
  skip_fsfstatus:
 	return retval;
@@ -1851,15 +2308,16 @@ zfcp_fsf_exchange_config_data_handler(st
 int
 zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
 {
-	int retval = 0;
+	volatile struct qdio_buffer_element *sbale;
 	unsigned long lock_flags;
+	int retval = 0;
 
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(erp_action->adapter,
 				     FSF_QTCB_OPEN_PORT_WITH_DID,
-				     &lock_flags,
 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
-				     &(erp_action->fsf_req));
+				     erp_action->adapter->pool.fsf_req_erp,
+				     &lock_flags, &(erp_action->fsf_req));
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
 			      "open port request for "
@@ -1870,6 +2328,11 @@ zfcp_fsf_open_port(struct zfcp_erp_actio
 		goto out;
 	}
 
+	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+                                    erp_action->fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
 	erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
 	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
 	erp_action->fsf_req->data.open_port.port = erp_action->port;
@@ -1912,8 +2375,11 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 	int retval = -EINVAL;
 	struct zfcp_port *port;
 	struct fsf_plogi *plogi;
+	struct fsf_qtcb_header *header;
+	u16 subtable, rule, counter;
 
 	port = fsf_req->data.open_port.port;
+	header = &fsf_req->qtcb->header;
 
 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
 		/* don't change port status in our bookkeeping */
@@ -1921,7 +2387,7 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 	}
 
 	/* evaluate FSF status in QTCB */
-	switch (fsf_req->qtcb->header.fsf_status) {
+	switch (header->fsf_status) {
 
 	case FSF_PORT_ALREADY_OPEN:
 		ZFCP_LOG_FLAGS(0, "FSF_PORT_ALREADY_OPEN\n");
@@ -1937,6 +2403,30 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 		 */
 		break;
 
+	case FSF_ACCESS_DENIED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+		ZFCP_LOG_NORMAL("Access denied, cannot open port "
+			"with WWPN 0x%Lx connected to the adapter %s\n",
+			port->wwpn, zfcp_get_busid_by_port(port));
+		counter = 0;
+		do {
+			subtable = header->fsf_status_qual.halfword[counter++];
+			rule = header->fsf_status_qual.halfword[counter++];
+			switch (subtable) {
+			case FSF_SQ_CFDC_SUBTABLE_OS:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+			case FSF_SQ_CFDC_SUBTABLE_LUN:
+				ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+					zfcp_act_subtable_type[subtable], rule);
+				break;
+			}
+		} while (counter < 4);
+		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+		zfcp_erp_port_failed(port);
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
 	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
 		ZFCP_LOG_FLAGS(1, "FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED\n");
 		ZFCP_LOG_INFO("error: The FSF adapter is out of resources. "
@@ -1952,7 +2442,7 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 
 	case FSF_ADAPTER_STATUS_AVAILABLE:
 		ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
-		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+		switch (header->fsf_status_qual.word[0]) {
 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
 			ZFCP_LOG_FLAGS(2,
 				       "FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
@@ -1982,12 +2472,12 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 		default:
 			ZFCP_LOG_NORMAL
 			    ("bug: Wrong status qualifier 0x%x arrived.\n",
-			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
+			     header->fsf_status_qual.word[0]);
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "fsf_sq_inval:");
 			debug_exception(
 				fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status_qual.word[0],
+				&header->fsf_status_qual.word[0],
 				sizeof (u32));
 			break;
 		}
@@ -1996,7 +2486,7 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 	case FSF_GOOD:
 		ZFCP_LOG_FLAGS(3, "FSF_GOOD\n");
 		/* save port handle assigned by FSF */
-		port->handle = fsf_req->qtcb->header.port_handle;
+		port->handle = header->port_handle;
 		ZFCP_LOG_INFO("The remote port (WWPN=0x%Lx) via adapter "
 			      "(busid=%s) was opened, it's "
 			      "port handle is 0x%x\n",
@@ -2055,11 +2545,10 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 	default:
 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
 				"(debug info 0x%x)\n",
-				fsf_req->qtcb->header.fsf_status);
+				header->fsf_status);
 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
 		debug_exception(fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status,
-				sizeof (u32));
+				&header->fsf_status, sizeof (u32));
 		break;
 	}
 
@@ -2079,15 +2568,16 @@ zfcp_fsf_open_port_handler(struct zfcp_f
 int
 zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
 {
-	int retval = 0;
+	volatile struct qdio_buffer_element *sbale;
 	unsigned long lock_flags;
+	int retval = 0;
 
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(erp_action->adapter,
 				     FSF_QTCB_CLOSE_PORT,
-				     &lock_flags,
 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
-				     &(erp_action->fsf_req));
+				     erp_action->adapter->pool.fsf_req_erp,
+				     &lock_flags, &(erp_action->fsf_req));
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create a "
 			      "close port request for WWPN 0x%Lx connected to "
@@ -2097,6 +2587,11 @@ zfcp_fsf_close_port(struct zfcp_erp_acti
 		goto out;
 	}
 
+	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+                                    erp_action->fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
 	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
 	erp_action->fsf_req->data.close_port.port = erp_action->port;
 	erp_action->fsf_req->erp_action = erp_action;
@@ -2153,7 +2648,7 @@ zfcp_fsf_close_port_handler(struct zfcp_
 		ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
 		ZFCP_LOG_INFO("Temporary port identifier (handle) 0x%x "
 			      "for the port with WWPN 0x%Lx connected to "
-			      "the adapter %s is"
+			      "the adapter %s is "
 			      "not valid. This may happen occasionally.\n",
 			      port->handle,
 			      port->wwpn, zfcp_get_busid_by_port(port));
@@ -2221,9 +2716,9 @@ zfcp_fsf_close_physical_port(struct zfcp
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(erp_action->adapter,
 				     FSF_QTCB_CLOSE_PHYSICAL_PORT,
-				     &lock_flags,
 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
-				     &erp_action->fsf_req);
+				     erp_action->adapter->pool.fsf_req_erp,
+				     &lock_flags, &erp_action->fsf_req);
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create a "
 			      "close physical port request for "
@@ -2280,8 +2775,11 @@ zfcp_fsf_close_physical_port_handler(str
 	int retval = -EINVAL;
 	struct zfcp_port *port;
 	struct zfcp_unit *unit;
+	struct fsf_qtcb_header *header;
+	u16 subtable, rule, counter;
 
 	port = fsf_req->data.close_physical_port.port;
+	header = &fsf_req->qtcb->header;
 
 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
 		/* don't change port status in our bookkeeping */
@@ -2289,7 +2787,7 @@ zfcp_fsf_close_physical_port_handler(str
 	}
 
 	/* evaluate FSF status in QTCB */
-	switch (fsf_req->qtcb->header.fsf_status) {
+	switch (header->fsf_status) {
 
 	case FSF_PORT_HANDLE_NOT_VALID:
 		ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
@@ -2302,7 +2800,7 @@ zfcp_fsf_close_physical_port_handler(str
 			      zfcp_get_busid_by_port(port));
 		ZFCP_LOG_DEBUG("status qualifier:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 1,
 				 "fsf_s_phand_nv");
@@ -2310,6 +2808,30 @@ zfcp_fsf_close_physical_port_handler(str
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
+	case FSF_ACCESS_DENIED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+		ZFCP_LOG_NORMAL("Access denied, cannot close "
+				"physical port with WWPN 0x%Lx connected to "
+				"the adapter %s\n", port->wwpn,
+				zfcp_get_busid_by_port(port));
+		counter = 0;
+		do {
+			subtable = header->fsf_status_qual.halfword[counter++];
+			rule = header->fsf_status_qual.halfword[counter++];
+			switch (subtable) {
+			case FSF_SQ_CFDC_SUBTABLE_OS:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+			case FSF_SQ_CFDC_SUBTABLE_LUN:
+	       			ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+					zfcp_act_subtable_type[subtable], rule);
+				break;
+			}
+		} while (counter < 4);
+		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
 	case FSF_PORT_BOXED:
 		ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
 		ZFCP_LOG_DEBUG("The remote port with WWPN 0x%Lx on the adapter "
@@ -2325,7 +2847,7 @@ zfcp_fsf_close_physical_port_handler(str
 
 	case FSF_ADAPTER_STATUS_AVAILABLE:
 		ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
-		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+		switch (header->fsf_status_qual.word[0]) {
 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
 			ZFCP_LOG_FLAGS(2,
 				       "FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
@@ -2345,13 +2867,12 @@ zfcp_fsf_close_physical_port_handler(str
 		default:
 			ZFCP_LOG_NORMAL
 			    ("bug: Wrong status qualifier 0x%x arrived.\n",
-			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
+			     header->fsf_status_qual.word[0]);
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "fsf_sq_inval:");
 			debug_exception(
 				fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status_qual.word[0],
-				sizeof (u32));
+				&header->fsf_status_qual.word[0], sizeof (u32));
 			break;
 		}
 		break;
@@ -2375,11 +2896,10 @@ zfcp_fsf_close_physical_port_handler(str
 	default:
 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
 				"(debug info 0x%x)\n",
-				fsf_req->qtcb->header.fsf_status);
+				header->fsf_status);
 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
 		debug_exception(fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status,
-				sizeof (u32));
+				&header->fsf_status, sizeof (u32));
 		break;
 	}
 
@@ -2403,15 +2923,16 @@ zfcp_fsf_close_physical_port_handler(str
 int
 zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
 {
-	int retval = 0;
+	volatile struct qdio_buffer_element *sbale;
 	unsigned long lock_flags;
+	int retval = 0;
 
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(erp_action->adapter,
 				     FSF_QTCB_OPEN_LUN,
-				     &lock_flags,
 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
-				     &(erp_action->fsf_req));
+				     erp_action->adapter->pool.fsf_req_erp,
+				     &lock_flags, &(erp_action->fsf_req));
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
 			      "open unit request for FCP-LUN 0x%Lx connected "
@@ -2423,6 +2944,11 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio
 		goto out;
 	}
 
+	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+                                    erp_action->fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
 	erp_action->fsf_req->qtcb->header.port_handle =
 		erp_action->port->handle;
 	erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
@@ -2430,6 +2956,8 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio
 	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;
+	erp_action->fsf_req->qtcb->bottom.support.option =
+		FSF_OPEN_LUN_SUPPRESS_BOXING;
 
 	/* start QDIO request for this FSF request */
 	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
@@ -2467,8 +2995,11 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 {
 	int retval = -EINVAL;
 	struct zfcp_unit *unit;
+	struct fsf_qtcb_header *header;
+	u16 subtable, rule, counter;
 
 	unit = fsf_req->data.open_unit.unit;
+	header = &fsf_req->qtcb->header;
 
 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
 		/* don't change unit status in our bookkeeping */
@@ -2476,19 +3007,19 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 	}
 
 	/* evaluate FSF status in QTCB */
-	switch (fsf_req->qtcb->header.fsf_status) {
+	switch (header->fsf_status) {
 
 	case FSF_PORT_HANDLE_NOT_VALID:
 		ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
 		ZFCP_LOG_INFO("Temporary port identifier (handle) 0x%x "
 			      "for the port with WWPN 0x%Lx connected to "
-			      "the adapter %s is"
+			      "the adapter %s is "
 			      "not valid. This may happen occasionally.\n",
 			      unit->port->handle,
 			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
 		ZFCP_LOG_DEBUG("status qualifier:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_ph_nv");
 		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
@@ -2508,6 +3039,32 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
+	case FSF_ACCESS_DENIED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+		ZFCP_LOG_NORMAL("Access denied, cannot open unit "
+				"with FCP-LUN 0x%Lx at the remote port with "
+				"WWPN 0x%Lx connected to the adapter %s\n",
+			unit->fcp_lun, unit->port->wwpn,
+			zfcp_get_busid_by_unit(unit));
+		counter = 0;
+		do {
+			subtable = header->fsf_status_qual.halfword[counter++];
+			rule = header->fsf_status_qual.halfword[counter++];
+			switch (subtable) {
+			case FSF_SQ_CFDC_SUBTABLE_OS:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+			case FSF_SQ_CFDC_SUBTABLE_LUN:
+				ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+					zfcp_act_subtable_type[subtable], rule);
+				break;
+			}
+		} while (counter < 4);
+		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+		zfcp_erp_unit_failed(unit);
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
 	case FSF_PORT_BOXED:
 		ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
 		ZFCP_LOG_DEBUG("The remote port "
@@ -2520,8 +3077,8 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 			ZFCP_STATUS_FSFREQ_RETRY;
 		break;
 
-	case FSF_LUN_IN_USE:
-		ZFCP_LOG_FLAGS(0, "FSF_LUN_IN_USE\n");
+	case FSF_LUN_SHARING_VIOLATION :
+		ZFCP_LOG_FLAGS(2, "FSF_LUN_SHARING_VIOLATION\n");
 		ZFCP_LOG_NORMAL("error: FCP-LUN 0x%Lx at "
 				"the remote port with WWPN 0x%Lx connected "
 				"to the adapter %s "
@@ -2530,12 +3087,23 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 				unit->fcp_lun,
 				unit->port->wwpn,
 				zfcp_get_busid_by_unit(unit));
+		subtable = header->fsf_status_qual.halfword[4];
+		rule = header->fsf_status_qual.halfword[5];
+		switch (subtable) {
+		case FSF_SQ_CFDC_SUBTABLE_OS:
+		case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+		case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+		case FSF_SQ_CFDC_SUBTABLE_LUN:
+			ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+				zfcp_act_subtable_type[subtable], rule);
+			break;
+		}
 		ZFCP_LOG_NORMAL("Additional sense data is presented:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 2,
-				 "fsf_s_l_in_use");
+				 "fsf_s_l_sh_vio");
 		zfcp_erp_unit_failed(unit);
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -2558,7 +3126,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 
 	case FSF_ADAPTER_STATUS_AVAILABLE:
 		ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
-		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+		switch (header->fsf_status_qual.word[0]) {
 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
 			ZFCP_LOG_FLAGS(2,
 				       "FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
@@ -2579,12 +3147,11 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 		default:
 			ZFCP_LOG_NORMAL
 			    ("bug: Wrong status qualifier 0x%x arrived.\n",
-			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
+			     header->fsf_status_qual.word[0]);
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "fsf_sq_inval:");
-			debug_exception(
-				fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status_qual.word[0],
+			debug_exception(fsf_req->adapter->erp_dbf, 0,
+					&header->fsf_status_qual.word[0],
 				sizeof (u32));
 		}
 		break;
@@ -2592,7 +3159,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 	case FSF_GOOD:
 		ZFCP_LOG_FLAGS(3, "FSF_GOOD\n");
 		/* save LUN handle assigned by FSF */
-		unit->handle = fsf_req->qtcb->header.lun_handle;
+		unit->handle = header->lun_handle;
 		ZFCP_LOG_TRACE("unit (FCP_LUN=0x%Lx) of remote port "
 			       "(WWPN=0x%Lx) via adapter (busid=%s) opened, "
 			       "port handle 0x%x \n",
@@ -2608,11 +3175,10 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 	default:
 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
 				"(debug info 0x%x)\n",
-				fsf_req->qtcb->header.fsf_status);
+				header->fsf_status);
 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
 		debug_exception(fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status,
-				sizeof (u32));
+				&header->fsf_status, sizeof (u32));
 		break;
 	}
 
@@ -2637,15 +3203,16 @@ zfcp_fsf_open_unit_handler(struct zfcp_f
 int
 zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
 {
-	int retval = 0;
+	volatile struct qdio_buffer_element *sbale;
 	unsigned long lock_flags;
+	int retval = 0;
 
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(erp_action->adapter,
 				     FSF_QTCB_CLOSE_LUN,
-				     &lock_flags,
 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
-				     &(erp_action->fsf_req));
+				     erp_action->adapter->pool.fsf_req_erp,
+				     &lock_flags, &(erp_action->fsf_req));
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create a "
 			      "close unit request for FCP-LUN 0x%Lx "
@@ -2657,6 +3224,11 @@ zfcp_fsf_close_unit(struct zfcp_erp_acti
 		goto out;
 	}
 
+	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
+                                    erp_action->fsf_req->sbal_curr, 0);
+        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
 	erp_action->fsf_req->qtcb->header.port_handle =
 	    erp_action->port->handle;
 	erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
@@ -2846,21 +3418,19 @@ zfcp_fsf_close_unit_handler(struct zfcp_
 int
 zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
 			       struct zfcp_unit *unit,
-			       Scsi_Cmnd * scsi_cmnd, int req_flags)
+			       struct scsi_cmnd * scsi_cmnd, int req_flags)
 {
 	struct zfcp_fsf_req *fsf_req = NULL;
 	struct fcp_cmnd_iu *fcp_cmnd_iu;
-	volatile struct qdio_buffer_element *buffere;
 	unsigned int sbtype;
 	unsigned long lock_flags;
 	int real_bytes = 0;
 	int retval = 0;
 
 	/* setup new FSF request */
-
-	retval = zfcp_fsf_req_create(adapter,
-				     FSF_QTCB_FCP_CMND,
-				     &lock_flags, req_flags, &(fsf_req));
+	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
+				     adapter->pool.fsf_req_scsi,
+				     &lock_flags, &fsf_req);
 	if (unlikely(retval < 0)) {
 		ZFCP_LOG_DEBUG("error: Out of resources. Could not create an "
 			       "FCP command request for FCP-LUN 0x%Lx "
@@ -2912,8 +3482,8 @@ zfcp_fsf_send_fcp_command_task(struct zf
 	 *      data direction bits in FCP_CMND IU
 	 */
 	switch (scsi_cmnd->sc_data_direction) {
-	case SCSI_DATA_NONE:
-		ZFCP_LOG_FLAGS(3, "SCSI_DATA_NONE\n");
+	case DMA_NONE:
+		ZFCP_LOG_FLAGS(3, "DMA_NONE\n");
 		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
 		/*
 		 * FIXME(qdio):
@@ -2922,20 +3492,20 @@ zfcp_fsf_send_fcp_command_task(struct zf
 		 */
 		sbtype = SBAL_FLAGS0_TYPE_READ;
 		break;
-	case SCSI_DATA_READ:
-		ZFCP_LOG_FLAGS(3, "SCSI_DATA_READ\n");
+	case DMA_FROM_DEVICE:
+		ZFCP_LOG_FLAGS(3, "DMA_FROM_DEVICE\n");
 		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
 		sbtype = SBAL_FLAGS0_TYPE_READ;
 		fcp_cmnd_iu->rddata = 1;
 		break;
-	case SCSI_DATA_WRITE:
-		ZFCP_LOG_FLAGS(3, "SCSI_DATA_WRITE\n");
+	case DMA_TO_DEVICE:
+		ZFCP_LOG_FLAGS(3, "DMA_TO_DEVICE\n");
 		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
 		sbtype = SBAL_FLAGS0_TYPE_WRITE;
 		fcp_cmnd_iu->wddata = 1;
 		break;
-	case SCSI_DATA_UNKNOWN:
-		ZFCP_LOG_FLAGS(0, "SCSI_DATA_UNKNOWN not supported\n");
+	case DMA_BIDIRECTIONAL:
+		ZFCP_LOG_FLAGS(0, "DMA_BIDIRECTIONAL not supported\n");
 	default:
 		/*
 		 * dummy, catch this condition earlier
@@ -2943,9 +3513,6 @@ zfcp_fsf_send_fcp_command_task(struct zf
 		 */
 		goto failed_scsi_cmnd;
 	}
-	buffere =
-	    &(adapter->request_queue.buffer[fsf_req->sbal_index]->element[0]);
-	buffere->flags |= sbtype;
 
 	/* set FC service class in QTCB (3 per default) */
 	fsf_req->qtcb->bottom.io.service_class = adapter->fc_service_class;
@@ -2984,29 +3551,24 @@ zfcp_fsf_send_fcp_command_task(struct zf
 		fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t);
 
 	/* generate SBALEs from data buffer */
-	real_bytes = zfcp_create_sbals_from_sg(fsf_req,
-					       scsi_cmnd,
-					       sbtype,
-					       0, ZFCP_MAX_SBALS_PER_REQ);
-	/* Note: >= and not = because the combined scatter-gather entries
-	 * may be larger than request_bufflen according to the mailing list
-	 */
-	if (likely(real_bytes >= scsi_cmnd->request_bufflen)) {
-		ZFCP_LOG_TRACE("Data fits\n");
-	} else if (likely(real_bytes == 0)) {
-		ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), "
+	real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd);
+	if (unlikely(real_bytes < 0)) {
+		if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) {
+			ZFCP_LOG_DEBUG(
+				"Data did not fit into available buffer(s), "
 			       "waiting for more...\n");
 		retval = -EIO;
-		goto no_fit;
 	} else {
 		ZFCP_LOG_NORMAL("error: No truncation implemented but "
-				"required. Shutting down unit (busid=%s, "
-				"WWPN=0x%16.16Lx, FCP_LUN=0x%16.16Lx)\n",
+					"required. Shutting down unit "
+					"(busid=%s, WWPN=0x%16.16Lx, "
+					"FCP_LUN=0x%16.16Lx)\n",
 				zfcp_get_busid_by_unit(unit),
 				unit->port->wwpn,
 				unit->fcp_lun);
 		zfcp_erp_unit_shutdown(unit, 0);
 		retval = -EINVAL;
+		}
 		goto no_fit;
 	}
 
@@ -3077,11 +3639,12 @@ zfcp_fsf_send_fcp_command_task_managemen
 	int retval = 0;
 	struct fcp_cmnd_iu *fcp_cmnd_iu;
 	unsigned long lock_flags;
-	volatile struct qdio_buffer_element *buffere;
+	volatile struct qdio_buffer_element *sbale;
 
 	/* setup new FSF request */
-	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND,
-				     &lock_flags, req_flags, &(fsf_req));
+	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
+				     adapter->pool.fsf_req_scsi,
+				     &lock_flags, &fsf_req);
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
 			      "FCP command (task management) request for "
@@ -3113,10 +3676,9 @@ zfcp_fsf_send_fcp_command_task_managemen
 	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
 		sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t);
 
-	buffere =
-	    &(adapter->request_queue.buffer[fsf_req->sbal_index]->element[0]);
-	buffere[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
-	buffere[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
+	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
 
 	/* set FCP related fields in FCP_CMND IU in QTCB */
 	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
@@ -3164,6 +3726,10 @@ zfcp_fsf_send_fcp_command_handler(struct
 {
 	int retval = -EINVAL;
 	struct zfcp_unit *unit;
+	struct fsf_qtcb_header *header;
+	u16 subtable, rule, counter;
+
+	header = &fsf_req->qtcb->header;
 
 	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
 		unit = fsf_req->data.send_fcp_command_task_management.unit;
@@ -3176,7 +3742,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 	}
 
 	/* evaluate FSF status in QTCB */
-	switch (fsf_req->qtcb->header.fsf_status) {
+	switch (header->fsf_status) {
 
 	case FSF_PORT_HANDLE_NOT_VALID:
 		ZFCP_LOG_FLAGS(1, "FSF_PORT_HANDLE_NOT_VALID\n");
@@ -3186,7 +3752,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 			      unit->port->handle,
 			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 1,
 				 "fsf_s_phand_nv");
@@ -3207,7 +3773,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 			      zfcp_get_busid_by_unit(unit));
 		ZFCP_LOG_NORMAL("Status qualifier data:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 1,
 				 "fsf_s_uhand_nv");
@@ -3229,14 +3795,14 @@ zfcp_fsf_send_fcp_command_handler(struct
 				zfcp_get_busid_by_unit(unit));
 		ZFCP_LOG_NORMAL("status qualifier:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 1,
 				 "fsf_s_hand_mis");
 		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
 		zfcp_cmd_dbf_event_fsf("handmism",
 				       fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -3261,7 +3827,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
 		zfcp_cmd_dbf_event_fsf("unsclass",
 				       fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -3278,18 +3844,43 @@ zfcp_fsf_send_fcp_command_handler(struct
 				unit->handle);
 		ZFCP_LOG_DEBUG("status qualifier:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
-			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
+			      (char *) &header->fsf_status_qual,
 			      sizeof (union fsf_status_qual));
 		debug_text_event(fsf_req->adapter->erp_dbf, 1,
 				 "fsf_s_fcp_lun_nv");
 		zfcp_erp_port_reopen(unit->port, 0);
 		zfcp_cmd_dbf_event_fsf("fluninv",
 				       fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 
+	case FSF_ACCESS_DENIED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
+		ZFCP_LOG_NORMAL("Access denied, cannot send FCP "
+				"command to the unit with FCP-LUN 0x%Lx at the "
+				"remote port with WWPN 0x%Lx connected to the "
+				"adapter %s\n",	unit->fcp_lun, unit->port->wwpn,
+			zfcp_get_busid_by_unit(unit));
+		counter = 0;
+		do {
+			subtable = header->fsf_status_qual.halfword[counter++];
+			rule = header->fsf_status_qual.halfword[counter++];
+			switch (subtable) {
+			case FSF_SQ_CFDC_SUBTABLE_OS:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
+			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
+			case FSF_SQ_CFDC_SUBTABLE_LUN:
+				ZFCP_LOG_NORMAL("Access denied (%s rule %d)\n",
+					zfcp_act_subtable_type[subtable], rule);
+				break;
+			}
+		} while (counter < 4);
+		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		break;
+
 	case FSF_DIRECTION_INDICATOR_NOT_VALID:
 		ZFCP_LOG_FLAGS(0, "FSF_DIRECTION_INDICATOR_NOT_VALID\n");
 		ZFCP_LOG_INFO("bug: Invalid data direction given for the unit "
@@ -3306,7 +3897,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
 		zfcp_cmd_dbf_event_fsf("dirinv",
 				       fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -3326,7 +3917,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
 		zfcp_cmd_dbf_event_fsf("idleninv",
 				       fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -3346,7 +3937,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 				 "fsf_s_out_dl_nv");
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
 		zfcp_cmd_dbf_event_fsf("odleninv", fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -3367,7 +3958,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
 		zfcp_cmd_dbf_event_fsf("cleninv",
 				       fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
@@ -3381,15 +3972,32 @@ zfcp_fsf_send_fcp_command_handler(struct
 		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
 		zfcp_erp_port_reopen(unit->port, 0);
 		zfcp_cmd_dbf_event_fsf("portbox", fsf_req,
-				       &fsf_req->qtcb->header.fsf_status_qual,
+				       &header->fsf_status_qual,
 				       sizeof (union fsf_status_qual));
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
 			ZFCP_STATUS_FSFREQ_RETRY;
 		break;
 
+	case FSF_LUN_BOXED:
+		ZFCP_LOG_FLAGS(0, "FSF_LUN_BOXED\n");
+		ZFCP_LOG_NORMAL(
+			"The remote unit with FCP-LUN 0x%Lx "
+			"at the remote port with WWPN 0x%Lx "
+			"connected to the adapter %s needs to be reopened\n",
+			unit->fcp_lun, unit->port->wwpn,
+			zfcp_get_busid_by_unit(unit));
+		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
+		zfcp_erp_unit_reopen(unit, 0);
+		zfcp_cmd_dbf_event_fsf("unitbox", fsf_req,
+			&header->fsf_status_qual,
+			sizeof(union fsf_status_qual));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
+			| ZFCP_STATUS_FSFREQ_RETRY;
+		break;
+
 	case FSF_ADAPTER_STATUS_AVAILABLE:
 		ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n");
-		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
+		switch (header->fsf_status_qual.word[0]) {
 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
 			ZFCP_LOG_FLAGS(2,
 				       "FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n");
@@ -3400,7 +4008,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 			zfcp_cmd_dbf_event_fsf(
 				"sqltest",
 				fsf_req,
-				&fsf_req->qtcb->header.fsf_status_qual,
+				&header->fsf_status_qual,
 				sizeof (union fsf_status_qual));
 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 			break;
@@ -3414,7 +4022,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 			zfcp_cmd_dbf_event_fsf(
 				"sqdeperp",
 				fsf_req,
-				&fsf_req->qtcb->header.fsf_status_qual,
+				&header->fsf_status_qual,
 				sizeof (union fsf_status_qual));
 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 			break;
@@ -3422,14 +4030,12 @@ zfcp_fsf_send_fcp_command_handler(struct
 			/* FIXME: shall we consider this a successful transfer? */
 			ZFCP_LOG_NORMAL
 			    ("bug: Wrong status qualifier 0x%x arrived.\n",
-			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
+			     header->fsf_status_qual.word[0]);
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "fsf_sq_inval:");
-			debug_exception(
-				fsf_req->adapter->erp_dbf,
-				0,
-				&fsf_req->qtcb->header.fsf_status_qual.word[0],
-				sizeof (u32));
+			debug_exception(fsf_req->adapter->erp_dbf, 0,
+					&header->fsf_status_qual.word[0],
+					sizeof(u32));
 			break;
 		}
 		break;
@@ -3445,8 +4051,7 @@ zfcp_fsf_send_fcp_command_handler(struct
 	default:
 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
 		debug_exception(fsf_req->adapter->erp_dbf, 0,
-				&fsf_req->qtcb->header.fsf_status,
-				sizeof (u32));
+				&header->fsf_status, sizeof(u32));
 		break;
 	}
 
@@ -3471,8 +4076,7 @@ static int
 zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
 {
 	int retval = 0;
-
-	Scsi_Cmnd *scpnt;
+	struct scsi_cmnd *scpnt;
 	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
 	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
 	struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *)
@@ -3874,6 +4478,310 @@ zfcp_fsf_send_fcp_command_task_managemen
 	return retval;
 }
 
+
+/*
+ * function:    zfcp_fsf_control_file
+ *
+ * purpose:     Initiator of the control file upload/download FSF requests
+ *
+ * returns:     0           - FSF request is successfuly created and queued
+ *              -EOPNOTSUPP - The FCP adapter does not have Control File support
+ *              -EINVAL     - Invalid direction specified
+ *              -ENOMEM     - Insufficient memory
+ *              -EPERM      - Cannot create FSF request or or place it in QDIO queue
+ */
+int
+zfcp_fsf_control_file(struct zfcp_adapter *adapter,
+                      struct zfcp_fsf_req **fsf_req_ptr,
+                      u32 fsf_command,
+                      u32 option,
+                      struct zfcp_sg_list *sg_list)
+{
+	struct zfcp_fsf_req *fsf_req;
+	struct fsf_qtcb_bottom_support *bottom;
+	volatile struct qdio_buffer_element *sbale;
+	unsigned long lock_flags;
+	int req_flags = 0;
+	int direction;
+	int retval = 0;
+
+#if 0
+	if (!(adapter->features & FSF_FEATURE_CFDC)) {
+		ZFCP_LOG_INFO(
+			"Adapter %s does not support control file\n",
+			zfcp_get_busid_by_adapter(adapter));
+		retval = -EOPNOTSUPP;
+		goto no_act_support;
+	}
+#endif
+
+	switch (fsf_command) {
+
+	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
+		direction = SBAL_FLAGS0_TYPE_WRITE;
+		if ((option != FSF_CFDC_OPTION_FULL_ACCESS) &&
+		    (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS))
+			req_flags = ZFCP_WAIT_FOR_SBAL;
+		break;
+
+	case FSF_QTCB_UPLOAD_CONTROL_FILE:
+		direction = SBAL_FLAGS0_TYPE_READ;
+		break;
+
+	default:
+		ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command);
+		goto invalid_command;
+	}
+
+	retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
+				     NULL, &lock_flags, &fsf_req);
+	if (retval < 0) {
+		ZFCP_LOG_INFO("error: Could not create FSF request for the "
+			      "adapter %s\n",
+			zfcp_get_busid_by_adapter(adapter));
+		retval = -EPERM;
+		goto out;
+	}
+
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+	sbale[0].flags |= direction;
+
+	bottom = &fsf_req->qtcb->bottom.support;
+	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
+	bottom->option = option;
+
+	if (sg_list->count > 0) {
+		int bytes;
+
+		bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction,
+						sg_list->sg, sg_list->count,
+						ZFCP_MAX_SBALS_PER_REQ);
+                if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) {
+			ZFCP_LOG_INFO(
+				"error: Could not create sufficient number of "
+				"SBALS for an FSF request to the adapter %s\n",
+				zfcp_get_busid_by_adapter(adapter));
+			retval = -ENOMEM;
+			goto sbals_failed;
+		}
+	} else {
+		sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	}
+
+	retval = zfcp_fsf_req_send(fsf_req, NULL);
+	if (retval < 0) {
+		ZFCP_LOG_INFO(
+			"error: Could not send FSF request to the adapter %s\n",
+			zfcp_get_busid_by_adapter(adapter));
+		retval = -EPERM;
+		goto queue_failed;
+	}
+
+	ZFCP_LOG_NORMAL(
+		"Control file %s FSF request has been sent to the adapter %s\n",
+		fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ?
+			"download" : "upload",
+		zfcp_get_busid_by_adapter(adapter));
+
+	*fsf_req_ptr = fsf_req;
+
+	goto out;
+
+sbals_failed:
+queue_failed:
+	zfcp_fsf_req_free(fsf_req);
+
+out:
+	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+
+invalid_command:
+	return retval;
+}
+
+
+/*
+ * function:    zfcp_fsf_control_file_handler
+ *
+ * purpose:     Handler of the control file upload/download FSF requests
+ *
+ * returns:     0       - FSF request successfuly processed
+ *              -EAGAIN - Operation has to be repeated because of a temporary problem
+ *              -EACCES - There is no permission to execute an operation
+ *              -EPERM  - The control file is not in a right format
+ *              -EIO    - There is a problem with the FCP adapter
+ *              -EINVAL - Invalid operation
+ *              -EFAULT - User space memory I/O operation fault
+ */
+static int
+zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req)
+{
+	struct zfcp_adapter *adapter = fsf_req->adapter;
+	struct fsf_qtcb_header *header = &fsf_req->qtcb->header;
+	struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support;
+	int retval = 0;
+
+	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+		retval = -EINVAL;
+		goto skip_fsfstatus;
+	}
+
+	switch (header->fsf_status) {
+
+	case FSF_GOOD:
+		ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
+		ZFCP_LOG_NORMAL(
+			"The FSF request has been successfully completed "
+			"on the adapter %s\n",
+			zfcp_get_busid_by_adapter(adapter));
+		break;
+
+	case FSF_OPERATION_PARTIALLY_SUCCESSFUL:
+		ZFCP_LOG_FLAGS(2, "FSF_OPERATION_PARTIALLY_SUCCESSFUL\n");
+		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) {
+			switch (header->fsf_status_qual.word[0]) {
+
+			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE:
+				ZFCP_LOG_NORMAL(
+					"CFDC of the adapter %s could not "
+					"be saved on the SE\n",
+					zfcp_get_busid_by_adapter(adapter));
+				break;
+
+			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2:
+				ZFCP_LOG_NORMAL(
+					"CFDC of the adapter %s could not "
+					"be copied to the secondary SE\n",
+					zfcp_get_busid_by_adapter(adapter));
+				break;
+
+			default:
+				ZFCP_LOG_NORMAL(
+					"CFDC could not be hardened "
+					"on the adapter %s\n",
+					zfcp_get_busid_by_adapter(adapter));
+			}
+		}
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EAGAIN;
+		break;
+
+	case FSF_AUTHORIZATION_FAILURE:
+		ZFCP_LOG_FLAGS(2, "FSF_AUTHORIZATION_FAILURE\n");
+		ZFCP_LOG_NORMAL(
+			"Adapter %s does not accept privileged commands\n",
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EACCES;
+		break;
+
+	case FSF_CFDC_ERROR_DETECTED:
+		ZFCP_LOG_FLAGS(2, "FSF_CFDC_ERROR_DETECTED\n");
+		ZFCP_LOG_NORMAL(
+			"Error at position %d in the CFDC, "
+			"CFDC is discarded by the adapter %s\n",
+			header->fsf_status_qual.word[0],
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EPERM;
+		break;
+
+	case FSF_CONTROL_FILE_UPDATE_ERROR:
+		ZFCP_LOG_FLAGS(2, "FSF_CONTROL_FILE_UPDATE_ERROR\n");
+		ZFCP_LOG_NORMAL(
+			"Adapter %s cannot harden the control file, "
+			"file is discarded\n",
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EIO;
+		break;
+
+	case FSF_CONTROL_FILE_TOO_LARGE:
+		ZFCP_LOG_FLAGS(2, "FSF_CONTROL_FILE_TOO_LARGE\n");
+		ZFCP_LOG_NORMAL(
+			"Control file is too large, file is discarded "
+			"by the adapter %s\n",
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EIO;
+		break;
+
+	case FSF_ACCESS_CONFLICT_DETECTED:
+		ZFCP_LOG_FLAGS(2, "FSF_ACCESS_CONFLICT_DETECTED\n");
+		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
+			ZFCP_LOG_NORMAL(
+				"CFDC has been discarded by the adapter %s, "
+				"because activation would impact "
+				"%d active connection(s)\n",
+				zfcp_get_busid_by_adapter(adapter),
+				header->fsf_status_qual.word[0]);
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EIO;
+		break;
+
+	case FSF_CONFLICTS_OVERRULED:
+		ZFCP_LOG_FLAGS(2, "FSF_CONFLICTS_OVERRULED\n");
+		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
+			ZFCP_LOG_NORMAL(
+				"CFDC has been activated on the adapter %s, "
+				"but activation has impacted "
+				"%d active connection(s)\n",
+				zfcp_get_busid_by_adapter(adapter),
+				header->fsf_status_qual.word[0]);
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EIO;
+		break;
+
+	case FSF_UNKNOWN_COMMAND:
+		ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n");
+		ZFCP_LOG_NORMAL(
+			"FSF command 0x%x is not supported by the adapter %s\n",
+			fsf_req->fsf_command,
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EINVAL;
+		break;
+
+	case FSF_UNKNOWN_OP_SUBTYPE:
+		ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n");
+		ZFCP_LOG_NORMAL(
+			"Invalid operation subtype 0x%x has been specified "
+			"in QTCB bottom sent to the adapter %s\n",
+			bottom->operation_subtype,
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EINVAL;
+		break;
+
+	case FSF_INVALID_COMMAND_OPTION:
+		ZFCP_LOG_FLAGS(2, "FSF_INVALID_COMMAND_OPTION\n");
+		ZFCP_LOG_NORMAL(
+			"Invalid option 0x%x has been specified "
+			"in QTCB bottom sent to the adapter %s\n",
+			bottom->option,
+			zfcp_get_busid_by_adapter(adapter));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EINVAL;
+		break;
+
+	default:
+		ZFCP_LOG_NORMAL(
+			"bug: An unknown/unexpected FSF status 0x%08x "
+			"was presented on the adapter %s\n",
+			header->fsf_status,
+			zfcp_get_busid_by_adapter(adapter));
+		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval");
+		debug_exception(fsf_req->adapter->erp_dbf, 0,
+			&header->fsf_status_qual.word[0], sizeof(u32));
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		retval = -EINVAL;
+		break;
+	}
+
+skip_fsfstatus:
+	return retval;
+}
+
+
 /*
  * function:    zfcp_fsf_req_wait_and_cleanup
  *
@@ -3931,6 +4839,54 @@ zfcp_fsf_req_create_sbal_check(unsigned 
 }
 
 /*
+ * set qtcb pointer in fsf_req and initialize QTCB
+ */
+static inline void
+zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd)
+{
+	if (likely(fsf_req->qtcb != NULL)) {
+		fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req;
+		fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
+		fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_cmd];
+		fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
+		fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req;
+		fsf_req->qtcb->header.fsf_command = fsf_cmd;
+	}
+}
+
+/**
+ * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
+ * @adapter: adapter for which request queue is examined
+ * @req_flags: flags indicating whether to wait for needed SBAL or not
+ * @lock_flags: lock_flags is queue_lock is taken
+ *
+ * locking: on success the queue_lock for the request queue of the adapter
+ *	is held
+ */
+static int
+zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
+		      unsigned long *lock_flags)
+{
+        int condition;
+        unsigned long timeout = ZFCP_SBAL_TIMEOUT;
+        struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
+
+        if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
+                ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq, timeout,
+                                        (condition =
+                                         (zfcp_fsf_req_create_sbal_check)
+                                         (lock_flags, req_queue, 1)));
+                if (!condition) {
+                        return -EIO;
+		}
+        } else if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) {
+                return -EIO;
+	}
+
+        return 0;
+}
+
+/*
  * function:    zfcp_fsf_req_create
  *
  * purpose:	create an FSF request at the specified adapter and
@@ -3947,149 +4903,65 @@ zfcp_fsf_req_create_sbal_check(unsigned 
  *		but is held on completion (write, irqsave)
  */
 int
-zfcp_fsf_req_create(struct zfcp_adapter *adapter,
-		    u32 fsf_cmd,
-		    unsigned long *lock_flags,
-		    int req_flags,
+zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
+		    mempool_t *pool, unsigned long *lock_flags,
 		    struct zfcp_fsf_req **fsf_req_p)
 {
+	volatile struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *fsf_req = NULL;
-	int retval = 0;
+	int ret = 0;
 	struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
-	volatile struct qdio_buffer_element *buffere;
-	unsigned long timeout;
-	int condition;
 
 	/* allocate new FSF request */
-	fsf_req = zfcp_fsf_req_alloc(adapter, fsf_cmd, GFP_ATOMIC);
-	if (unlikely(!fsf_req)) {
+	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
+	if (unlikely(NULL == fsf_req)) {
 		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
 			       "the outbound (send) queue.\n");
-		retval = -ENOMEM;
+		ret = -ENOMEM;
 		goto failed_fsf_req;
 	}
-	/* save pointer to "parent" adapter */
-	fsf_req->adapter = adapter;
+
+        zfcp_fsf_req_qtcb_init(fsf_req, fsf_cmd);
 
 	/* initialize waitqueue which may be used to wait on 
 	   this request completion */
 	init_waitqueue_head(&fsf_req->completion_wq);
 
+        ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
+        if(ret < 0) {
+                goto failed_sbals;
+	}
+
+
 	/* set magics */
 	fsf_req->common_magic = ZFCP_MAGIC;
 	fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ;
 
+	fsf_req->adapter = adapter;	/* pointer to "parent" adapter */
 	fsf_req->fsf_command = fsf_cmd;
-	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
-		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
+	fsf_req->sbal_number = 1;
+	fsf_req->sbal_first = req_queue->free_index;
+	fsf_req->sbal_curr = req_queue->free_index;
+        fsf_req->sbale_curr = 1;
 
-	/* initialize QTCB */
-	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;
-		fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
-		fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_cmd];
-		fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
-		fsf_req->qtcb->header.req_handle = (unsigned long) fsf_req;
-		fsf_req->qtcb->header.fsf_command = fsf_cmd;
-		/*
-		 * Request Sequence Number is set later when the request is
-		 * actually sent.
-		 */
+	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) {
+		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
 	}
 
-	/*
-	 * 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 (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
-		timeout = ZFCP_SBAL_TIMEOUT;
-		ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq,
-					timeout,
-					(condition =
-					 (zfcp_fsf_req_create_sbal_check)
-					 (lock_flags, req_queue, 1)));
-		if (!condition) {
-			retval = -EIO;
-			goto failed_sbals;
-		}
-	} else {
-		if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) {
-			retval = -EIO;
-			goto failed_sbals;
-		}
-	}
-	fsf_req->sbal_count = 1;
-	fsf_req->sbal_index = req_queue->free_index;
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
 
-	ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
-		       fsf_req->sbal_count, fsf_req->sbal_index);
-	buffere = req_queue->buffer[fsf_req->sbal_index]->element;
 	/* setup common SBALE fields */
-	buffere[0].addr = fsf_req;
-	buffere[0].flags |= SBAL_FLAGS0_COMMAND;
-	if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
-		buffere[1].addr = (void *) fsf_req->qtcb;
-		buffere[1].length = ZFCP_QTCB_SIZE;
-	}
-
-	/* set specific common SBALE and QTCB fields */
-	switch (fsf_cmd) {
-	case FSF_QTCB_FCP_CMND:
-		ZFCP_LOG_FLAGS(3, "FSF_QTCB_FCP_CMND\n");
-		/*
-		 * storage-block type depends on actual
-		 * SCSI command and is set by calling
-		 * routine according to transfer direction
-		 * of data buffers associated with SCSI
-		 * command
-		 */
-		break;
-	case FSF_QTCB_ABORT_FCP_CMND:
-	case FSF_QTCB_OPEN_PORT_WITH_DID:
-	case FSF_QTCB_OPEN_LUN:
-	case FSF_QTCB_CLOSE_LUN:
-	case FSF_QTCB_CLOSE_PORT:
-	case FSF_QTCB_CLOSE_PHYSICAL_PORT:
-	case FSF_QTCB_SEND_ELS:	/* FIXME: ELS needs separate case */
-		ZFCP_LOG_FLAGS(3, "FSF_QTCB_*\n");
-		/*
-		 * FIXME(qdio):
-		 * what is the correct type for commands
-		 * without 'real' data buffers?
-		 */
-		buffere[0].flags |= SBAL_FLAGS0_TYPE_READ;
-		buffere[1].flags |= SBAL_FLAGS_LAST_ENTRY;
-		break;
-	case FSF_QTCB_EXCHANGE_CONFIG_DATA:
-		ZFCP_LOG_FLAGS(3, "FSF_QTCB_EXCHANGE_CONFIG_DATA\n");
-		buffere[0].flags |= SBAL_FLAGS0_TYPE_READ;
-		buffere[1].flags |= SBAL_FLAGS_LAST_ENTRY;
-		break;
-
-	case FSF_QTCB_SEND_GENERIC:
-		ZFCP_LOG_FLAGS(3, "FSF_QTCB_SEND_GENERIC\n");
-		buffere[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
-		break;
-
-	case FSF_QTCB_UNSOLICITED_STATUS:
-		ZFCP_LOG_FLAGS(3, "FSF_QTCB_UNSOLICITED_STATUS\n");
-		buffere[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
-		buffere[2].flags |= SBAL_FLAGS_LAST_ENTRY;
-		break;
-
-	default:
-		ZFCP_LOG_NORMAL("bug: An attempt to send an unsupported "
-				"command has been detected. "
-				"(debug info 0x%x)\n", fsf_cmd);
-		goto unsupported_fsf_cmd;
+	sbale[0].addr = fsf_req;
+	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
+	if (likely(fsf_req->qtcb != NULL)) {
+		sbale[1].addr = (void *) fsf_req->qtcb;
+		sbale[1].length = sizeof(struct fsf_qtcb);
 	}
 
-	/* yes, we did it - skip all cleanups for different failures */
-	goto out;
+	ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
+                       fsf_req->sbal_number, fsf_req->sbal_first);
 
- unsupported_fsf_cmd:
+	goto success;
 
  failed_sbals:
 #ifdef ZFCP_STAT_QUEUES
@@ -4101,9 +4973,9 @@ zfcp_fsf_req_create(struct zfcp_adapter 
 
  failed_fsf_req:
 	write_lock_irqsave(&req_queue->queue_lock, *lock_flags);
- out:
+ success:
 	*fsf_req_p = fsf_req;
-	return retval;
+	return ret;
 }
 
 /*
@@ -4117,23 +4989,24 @@ zfcp_fsf_req_create(struct zfcp_adapter 
 static int
 zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
 {
-	int retval = 0;
-	struct zfcp_adapter *adapter = fsf_req->adapter;
-	struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
-	volatile struct qdio_buffer_element *buffere;
-	int inc_seq_no = 1;
+	struct zfcp_adapter *adapter;
+	struct zfcp_qdio_queue *req_queue;
+	volatile struct qdio_buffer_element *sbale;
 	int new_distance_from_int;
 	unsigned long flags;
+	int inc_seq_no = 1;
+	int retval = 0;
+
+	adapter = fsf_req->adapter;
+	req_queue = &adapter->request_queue,
 
-	u8 sbal_index = fsf_req->sbal_index;
 
 	/* FIXME(debug): remove it later */
-	buffere = &(req_queue->buffer[sbal_index]->element[0]);
-	ZFCP_LOG_DEBUG("zeroeth BUFFERE flags=0x%x \n ", buffere->flags);
-	buffere = &(req_queue->buffer[sbal_index]->element[1]);
-	ZFCP_LOG_TRACE("HEX DUMP OF 0eth BUFFERE PAYLOAD:\n");
-	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) buffere->addr,
-		      buffere->length);
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0);
+	ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags);
+	ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n");
+	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
+		      sbale[1].length);
 
 	/* set sequence counter in QTCB */
 	if (likely(fsf_req->qtcb)) {
@@ -4168,24 +5041,22 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 		       "index_in_queue=%i, count=%i, buffers=0x%lx\n",
 		       zfcp_get_busid_by_adapter(adapter),
 		       QDIO_FLAG_SYNC_OUTPUT,
-		       0,
-		       sbal_index,
-		       fsf_req->sbal_count,
-		       (unsigned long) &req_queue->buffer[sbal_index]);
+		       0, fsf_req->sbal_first, fsf_req->sbal_number,
+		       (unsigned long) &req_queue->buffer[fsf_req->sbal_first]);
 
 	/*
 	 * adjust the number of free SBALs in request queue as well as
 	 * position of first one
 	 */
-	atomic_sub(fsf_req->sbal_count, &req_queue->free_count);
+	atomic_sub(fsf_req->sbal_number, &req_queue->free_count);
 	ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count));
-	req_queue->free_index += fsf_req->sbal_count;	  /* increase */
+	req_queue->free_index += fsf_req->sbal_number;	  /* increase */
 	req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q;  /* wrap if needed */
 	new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req);
 
 	retval = do_QDIO(adapter->ccw_device,
 			 QDIO_FLAG_SYNC_OUTPUT,
-			 0, fsf_req->sbal_index, fsf_req->sbal_count, NULL);
+			 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
 
 	if (unlikely(retval)) {
 		/* Queues are down..... */
@@ -4204,9 +5075,9 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f
 		 * position of first one
 		 */
 		zfcp_qdio_zero_sbals(req_queue->buffer,
-				     fsf_req->sbal_index, fsf_req->sbal_count);
-		atomic_add(fsf_req->sbal_count, &req_queue->free_count);
-		req_queue->free_index -= fsf_req->sbal_count;	 /* increase */
+				     fsf_req->sbal_first, fsf_req->sbal_number);
+		atomic_add(fsf_req->sbal_number, &req_queue->free_count);
+		req_queue->free_index -= fsf_req->sbal_number;	 /* increase */
 		req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q;
 		req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
 		ZFCP_LOG_DEBUG
@@ -4270,35 +5141,4 @@ zfcp_fsf_req_cleanup(struct zfcp_fsf_req
 	zfcp_fsf_req_free(fsf_req);
 }
 
-/*
- * try to allocate fsf_req with QTCB,
- * alternately try to get hold of fsf_req+QTCB provided by the specified memory
- * pool element, this routine is called for all kinds of fsf requests other than
- * status read since status read does neither require kmalloc involvement
- * nor a QTCB
- */
-static struct zfcp_fsf_req *
-zfcp_fsf_req_get(int kmalloc_flags, mempool_t * pool)
-{
-	struct zfcp_fsf_req *fsf_req;
-
-	fsf_req = kmalloc(ZFCP_QTCB_AND_REQ_SIZE, kmalloc_flags);
-	if (likely(fsf_req)) {
-		memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
-	} else {
-		fsf_req = mempool_alloc(pool, kmalloc_flags);
-		if (likely(fsf_req)) {
-			memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
-			fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
-		}
-	}
-	if (likely(fsf_req))
-		fsf_req->qtcb =
-		    (struct fsf_qtcb *) ((unsigned long) fsf_req +
-					 sizeof (struct zfcp_fsf_req));
-
-	return fsf_req;
-}
-
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_fsf.h~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_fsf.h
--- 25/drivers/s390/scsi/zfcp_fsf.h~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_fsf.h	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  * 
  * FCP adapter driver for IBM eServer zSeries 
  * 
- * Copyright 2002 IBM Corporation 
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
- *            Aron Zeh <arzeh@de.ibm.com> 
- *            Wolfgang Taphorn <taphorn@de.ibm.com> 
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com> 
  *            Heiko Carstens <heiko.carstens@de.ibm.com> 
  * 
@@ -44,11 +45,22 @@
 #define	FSF_QTCB_SEND_ELS			0x0000000B
 #define	FSF_QTCB_SEND_GENERIC			0x0000000C
 #define	FSF_QTCB_EXCHANGE_CONFIG_DATA		0x0000000D
+#define	FSF_QTCB_EXCHANGE_PORT_DATA		0x0000000E
+#define FSF_QTCB_DOWNLOAD_CONTROL_FILE		0x00000012
+#define FSF_QTCB_UPLOAD_CONTROL_FILE		0x00000013
 
 /* FSF QTCB types */
 #define FSF_IO_COMMAND				0x00000001
 #define FSF_SUPPORT_COMMAND			0x00000002
 #define FSF_CONFIG_COMMAND			0x00000003
+#define FSF_PORT_COMMAND			0x00000004
+
+/* FSF control file upload/download operations' subtype and options */
+#define FSF_CFDC_OPERATION_SUBTYPE		0x00020001
+#define FSF_CFDC_OPTION_NORMAL_MODE		0x00000000
+#define FSF_CFDC_OPTION_FORCE			0x00000001
+#define FSF_CFDC_OPTION_FULL_ACCESS		0x00000002
+#define FSF_CFDC_OPTION_RESTRICTED_ACCESS	0x00000004
 
 /* FSF protocol stati */
 #define FSF_PROT_GOOD				0x00000001
@@ -71,9 +83,9 @@
 #define FSF_HANDLE_MISMATCH			0x00000005
 #define FSF_SERVICE_CLASS_NOT_SUPPORTED		0x00000006
 #define FSF_FCPLUN_NOT_VALID			0x00000009
-//#define FSF_ACCESS_DENIED                     0x00000010
+#define FSF_ACCESS_DENIED			0x00000010
 #define FSF_ACCESS_TYPE_NOT_VALID		0x00000011
-#define FSF_LUN_IN_USE				0x00000012
+#define FSF_LUN_SHARING_VIOLATION               0x00000012
 #define FSF_COMMAND_ABORTED_ULP			0x00000020
 #define FSF_COMMAND_ABORTED_ADAPTER		0x00000021
 #define FSF_FCP_COMMAND_DOES_NOT_EXIST		0x00000022
@@ -87,13 +99,24 @@
 #define FSF_RESPONSE_BUF_NOT_VALID		0x00000043
 #define FSF_ELS_COMMAND_REJECTED		0x00000050
 #define FSF_GENERIC_COMMAND_REJECTED		0x00000051
-//#define FSF_AUTHORIZATION_FAILURE             0x00000053
+#define FSF_OPERATION_PARTIALLY_SUCCESSFUL	0x00000052
+#define FSF_AUTHORIZATION_FAILURE		0x00000053
+#define FSF_CFDC_ERROR_DETECTED			0x00000054
+#define FSF_CONTROL_FILE_UPDATE_ERROR		0x00000055
+#define FSF_CONTROL_FILE_TOO_LARGE		0x00000056
+#define FSF_ACCESS_CONFLICT_DETECTED		0x00000057
+#define FSF_CONFLICTS_OVERRULED			0x00000058
 #define FSF_PORT_BOXED				0x00000059
-//#define FSF_LUN_BOXED                         0x0000005A
+#define FSF_LUN_BOXED				0x0000005A
+#define FSF_PAYLOAD_SIZE_MISMATCH		0x00000060
+#define FSF_REQUEST_SIZE_TOO_LARGE		0x00000061
+#define FSF_RESPONSE_SIZE_TOO_LARGE		0x00000062
 #define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
 #define FSF_FCP_RSP_AVAILABLE			0x000000AF
 #define FSF_UNKNOWN_COMMAND			0x000000E2
-//#define FSF_ERROR                             0x000000FF 
+#define FSF_UNKNOWN_OP_SUBTYPE                  0x000000E3
+#define FSF_INVALID_COMMAND_OPTION              0x000000E5
+/* #define FSF_ERROR                             0x000000FF  */
 
 #define FSF_STATUS_QUALIFIER_SIZE		16
 
@@ -107,6 +130,15 @@
 #define FSF_SQ_COMMAND_ABORTED			0x06
 #define FSF_SQ_NO_RETRY_POSSIBLE		0x07
 
+/* FSF status qualifier for CFDC commands */
+#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE	0x00000001
+#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2	0x00000002
+/* CFDC subtable codes */
+#define FSF_SQ_CFDC_SUBTABLE_OS			0x0001
+#define FSF_SQ_CFDC_SUBTABLE_PORT_WWPN		0x0002
+#define FSF_SQ_CFDC_SUBTABLE_PORT_DID		0x0003
+#define FSF_SQ_CFDC_SUBTABLE_LUN		0x0004
+
 /* FSF status qualifier (most significant 4 bytes), local link down */
 #define FSF_PSQ_LINK_NOLIGHT			0x00000004
 #define FSF_PSQ_LINK_WRAPPLUG			0x00000008
@@ -124,11 +156,20 @@
 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD	0x00000004
 #define FSF_STATUS_READ_LINK_DOWN		0x00000005 /* FIXME: really? */
 #define FSF_STATUS_READ_LINK_UP          	0x00000006
+#define FSF_STATUS_READ_NOTIFICATION_LOST	0x00000009
+#define FSF_STATUS_READ_CFDC_UPDATED		0x0000000A
+#define FSF_STATUS_READ_CFDC_HARDENED		0x0000000B
 
 /* status subtypes in status read buffer */
 #define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT	0x00000001
 #define FSF_STATUS_READ_SUB_ERROR_PORT		0x00000002
 
+/* status subtypes for CFDC */
+#define FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED	0x00000020
+#define FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED	0x00000040
+#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE	0x00000002
+#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
+
 /* topologie that is detected by the adapter */
 #define FSF_TOPO_ERROR				0x00000000
 #define FSF_TOPO_P2P				0x00000001
@@ -149,10 +190,48 @@
 
 /* SBAL chaining */
 #define FSF_MAX_SBALS_PER_REQ			36
+#define FSF_MAX_SBALS_PER_ELS_REQ		2
 
 /* logging space behind QTCB */
 #define FSF_QTCB_LOG_SIZE			1024
 
+/* channel features */
+#define FSF_FEATURE_QTCB_SUPPRESSION            0x00000001
+#define FSF_FEATURE_CFDC			0x00000002
+#define FSF_FEATURE_SENSEDATA_REPLICATION       0x00000004
+#define FSF_FEATURE_LOST_SAN_NOTIFICATION       0x00000008
+#define FSF_FEATURE_HBAAPI_MANAGEMENT           0x00000010
+#define FSF_FEATURE_ELS_CT_CHAINED_SBALS        0x00000020
+
+/* option */
+#define FSF_OPEN_LUN_SUPPRESS_BOXING		0x00000001
+
+/* adapter types */
+#define FSF_ADAPTER_TYPE_FICON                  0x00000001
+#define FSF_ADAPTER_TYPE_FICON_EXPRESS          0x00000002
+
+/* port types */
+#define FSF_HBA_PORTTYPE_UNKNOWN		0x00000001
+#define FSF_HBA_PORTTYPE_NOTPRESENT		0x00000003
+#define FSF_HBA_PORTTYPE_NPORT			0x00000005
+#define FSF_HBA_PORTTYPE_PTP			0x00000021
+/* following are not defined and used by FSF Spec
+   but are additionally defined by FC-HBA */
+#define FSF_HBA_PORTTYPE_OTHER			0x00000002
+#define FSF_HBA_PORTTYPE_NOTPRESENT		0x00000003
+#define FSF_HBA_PORTTYPE_NLPORT			0x00000006
+#define FSF_HBA_PORTTYPE_FLPORT			0x00000007
+#define FSF_HBA_PORTTYPE_FPORT			0x00000008
+#define FSF_HBA_PORTTYPE_LPORT			0x00000020
+
+/* port states */
+#define FSF_HBA_PORTSTATE_UNKNOWN		0x00000001
+#define FSF_HBA_PORTSTATE_ONLINE		0x00000002
+#define FSF_HBA_PORTSTATE_OFFLINE		0x00000003
+#define FSF_HBA_PORTSTATE_LINKDOWN		0x00000006
+#define FSF_HBA_PORTSTATE_ERROR			0x00000007
+
+
 struct fsf_queue_designator;
 struct fsf_status_read_buffer;
 struct fsf_port_closed_payload;
@@ -307,49 +386,92 @@ struct fsf_qtcb_bottom_io {
 } __attribute__ ((packed));
 
 struct fsf_qtcb_bottom_support {
-	u8  res1[16];
+	u32 operation_subtype;
+	u8  res1[12];
 	u32 d_id;
-	u32 res2;
+	u32 option;
 	u64 fcp_lun;
-	u64 res3;
+	u64 res2;
 	u64 req_handle;
 	u32 service_class;
-	u8  res4[3];
+	u8 res3[3];
 	u8  timeout;
-	u8  res5[184];
+	u8 res4[184];
 	u32 els1_length;
 	u32 els2_length;
-	u64 res6;
+	u32 req_buf_length;
+	u32 resp_buf_length;
 	u8  els[256];
 } __attribute__ ((packed));
 
 struct fsf_qtcb_bottom_config {
 	u32 lic_version;
-	u32 res1;
+	u32 feature_selection;
 	u32 high_qtcb_version;
 	u32 low_qtcb_version;
 	u32 max_qtcb_size;
-	u8  res2[12];
+	u32 max_data_transfer_size;
+	u32 supported_features;
+	u8  res1[4];
 	u32 fc_topology;
 	u32 fc_link_speed;
 	u32 adapter_type;
 	u32 peer_d_id;
-	u8  res3[12];
+	u8 res2[12];
 	u32 s_id;
 	struct fsf_nport_serv_param nport_serv_param;
-	u8  res4[320];
+	u8 res3[8];
+	u32 adapter_ports;
+	u32 hardware_version;
+	u8 serial_number[32];
+	u8 res4[272];
+} __attribute__ ((packed));
+
+struct fsf_qtcb_bottom_port {
+	u8 res1[8];
+	u32 fc_port_id;
+	u32 port_type;
+	u32 port_state;
+	u32 class_of_service;	/* should be 0x00000006 for class 2 and 3 */
+	u8 supported_fc4_types[32]; /* should be 0x00000100 for scsi fcp */
+	u8 active_fc4_types[32];
+	u32 supported_speed;	/* 0x0001 for 1 GBit/s or 0x0002 for 2 GBit/s */
+	u32 maximum_frame_size;	/* fixed value of 2112 */
+	u64 seconds_since_last_reset;
+	u64 tx_frames;
+	u64 tx_words;
+	u64 rx_frames;
+	u64 rx_words;
+	u64 lip;		/* 0 */
+	u64 nos;		/* currently 0 */
+	u64 error_frames;	/* currently 0 */
+	u64 dumped_frames;	/* currently 0 */
+	u64 link_failure;
+	u64 loss_of_sync;
+	u64 loss_of_signal;
+	u64 psp_error_counts;
+	u64 invalid_tx_words;
+	u64 invalid_crcs;
+	u64 input_requests;
+	u64 output_requests;
+	u64 control_requests;
+	u64 input_mb;		/* where 1 MByte == 1.000.000 Bytes */
+	u64 output_mb;		/* where 1 MByte == 1.000.000 Bytes */
+	u8 res2[256];
 } __attribute__ ((packed));
 
 union fsf_qtcb_bottom {
 	struct fsf_qtcb_bottom_io      io;
 	struct fsf_qtcb_bottom_support support;
 	struct fsf_qtcb_bottom_config  config;
+	struct fsf_qtcb_bottom_port port;
 };
 
 struct fsf_qtcb {
 	struct fsf_qtcb_prefix prefix;
 	struct fsf_qtcb_header header;
 	union  fsf_qtcb_bottom bottom;
+	u8 log[FSF_QTCB_LOG_SIZE];
 } __attribute__ ((packed));
 
 #endif				/* FSF_H */
diff -puN drivers/s390/scsi/zfcp_qdio.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_qdio.c
--- 25/drivers/s390/scsi/zfcp_qdio.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_qdio.c	Fri Feb 20 16:00:58 2004
@@ -5,11 +5,12 @@
  *
  * QDIO related routines
  *
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Authors:
  *      Martin Peschke <mpeschke@de.ibm.com>
  *      Raimund Schroeder <raimund.schroeder@de.ibm.com>
- *      Wolfgang Taphorn <taphorn@de.ibm.com>
+ *      Wolfgang Taphorn
  *      Heiko Carstens <heiko.carstens@de.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -27,10 +28,28 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_QDIO_C_REVISION "$Revision: 1.10 $"
+#define ZFCP_QDIO_C_REVISION "$Revision: 1.13 $"
 
 #include "zfcp_ext.h"
 
+static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
+	(struct zfcp_qdio_queue *, int, int);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
+	(struct zfcp_fsf_req *, int, int);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+	(struct zfcp_fsf_req *, unsigned long);
+static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+	(struct zfcp_fsf_req *, unsigned long);
+static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
+static inline void zfcp_qdio_sbale_fill
+	(struct zfcp_fsf_req *, unsigned long, void *, int);
+static inline int zfcp_qdio_sbals_from_segment
+	(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
+static inline int zfcp_qdio_sbals_from_buffer
+	(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
+
 static qdio_handler_t zfcp_qdio_request_handler;
 static qdio_handler_t zfcp_qdio_response_handler;
 static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
@@ -38,7 +57,6 @@ static int zfcp_qdio_handler_error_check
 					 unsigned int, unsigned int);
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_QDIO
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_QDIO
 
 /*
  * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t 
@@ -318,7 +336,7 @@ zfcp_qdio_request_handler(struct ccw_dev
 	atomic_add(elements_processed, &queue->free_count);
 	ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count));
 	wake_up(&adapter->request_wq);
-	ZFCP_LOG_DEBUG("Elements_processed = %d, free count=%d \n",
+	ZFCP_LOG_DEBUG("Elements_processed = %d, free count=%d\n",
 		       elements_processed, atomic_read(&queue->free_count));
  out:
 	return;
@@ -365,7 +383,7 @@ zfcp_qdio_response_handler(struct ccw_de
 	 */
 
 	buffere = &(queue->buffer[first_element]->element[0]);
-	ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x \n ", buffere->flags);
+	ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x \n", buffere->flags);
 	/*
 	 * go through all SBALs from input queue currently
 	 * returned by QDIO layer
@@ -516,8 +534,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 		       (unsigned long) fsf_req, (unsigned long) 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);
+		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb,
+			      sizeof(struct fsf_qtcb));
 	}
 
 	/* finish the FSF request */
@@ -526,24 +544,346 @@ zfcp_qdio_reqid_check(struct zfcp_adapte
 	return retval;
 }
 
+/**
+ * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue
+ * @queue: queue from which SBALE should be returned
+ * @sbal: specifies number of SBAL in queue
+ * @sbale: specifes number of SBALE in SBAL
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
+{
+	return &queue->buffer[sbal]->element[sbale];
+}
+
+/**
+ * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
+ *	a struct zfcp_fsf_req
+ */
+inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
+{
+	return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
+				   sbal, sbale);
+}
+
+/**
+ * zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for
+ *	a struct zfcp_fsf_req
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
+{
+	return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue,
+				   sbal, sbale);
+}
+
+/**
+ * zfcp_qdio_sbale_curr - return current SBALE on request_queue for
+ *	a struct zfcp_fsf_req
+ */
+inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
+{
+	return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
+				   fsf_req->sbale_curr);
+}
+
+/**
+ * zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used
+ *	on the request_queue for a struct zfcp_fsf_req
+ * @fsf_req: the number of the last SBAL that can be used is stored herein
+ * @max_sbals: used to pass an upper limit for the number of SBALs
+ *
+ * Note: We can assume at least one free SBAL in the request_queue when called.
+ */
+static inline void
+zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
+{
+	int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
+	count = min(count, max_sbals);
+	fsf_req->sbal_last  = fsf_req->sbal_first;
+	fsf_req->sbal_last += (count - 1);
+	fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
+}
+
+/**
+ * zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a
+ *	request
+ * @fsf_req: zfcp_fsf_req to be processed
+ * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL
+ *
+ * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
+{
+	volatile struct qdio_buffer_element *sbale;
+
+	/* set last entry flag in current SBALE of current SBAL */
+	sbale = zfcp_qdio_sbale_curr(fsf_req);
+	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+
+	/* don't exceed last allowed SBAL */
+	if (fsf_req->sbal_curr == fsf_req->sbal_last)
+		return NULL;
+
+	/* set chaining flag in first SBALE of current SBAL */
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+	sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
+
+	/* calculate index of next SBAL */
+	fsf_req->sbal_curr++;
+	fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q;
+
+	/* keep this requests number of SBALs up-to-date */
+	fsf_req->sbal_number++;
+
+	/* start at first SBALE of new SBAL */
+	fsf_req->sbale_curr = 0;
+
+	/* set storage-block type for new SBAL */
+	sbale = zfcp_qdio_sbale_curr(fsf_req);
+	sbale->flags |= sbtype;
+
+	return sbale;
+}
+
+/**
+ * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
+ */
+static inline volatile struct qdio_buffer_element *
+zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
+{
+	if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
+		return zfcp_qdio_sbal_chain(fsf_req, sbtype);
+
+	fsf_req->sbale_curr++;
+
+	return zfcp_qdio_sbale_curr(fsf_req);
+}
+
+/**
+ * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
+ *	with zero from
+ */
+static inline int
+zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
+{
+	struct qdio_buffer **buf = queue->buffer;
+	int curr = first;
+	int count = 0;
+
+	for(;;) {
+		curr %= QDIO_MAX_BUFFERS_PER_Q;
+		count++;
+		memset(buf[curr], 0, sizeof(struct qdio_buffer));
+		if (curr == last)
+			break;
+		curr++;
+	}
+	return count;
+}
+
+
+/**
+ * zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req
+ */
+static inline int
+zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
+{
+	return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue,
+				    fsf_req->sbal_first, fsf_req->sbal_curr);
+}
+
+
+/**
+ * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
+ *	on request_queue
+ */
+static inline void
+zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+		     void *addr, int length)
+{
+	volatile struct qdio_buffer_element *sbale;
+
+	sbale = zfcp_qdio_sbale_curr(fsf_req);
+	sbale->addr = addr;
+	sbale->length = length;
+
+#ifdef ZFCP_STAT_REQSIZES
+        if (sbtype == SBAL_FLAGS0_TYPE_READ)
+                zfcp_statistics_inc(&zfcp_data.read_sg_head, length);
+        else    zfcp_statistics_inc(&zfcp_data.write_sg_head, length);
+#endif
+}
+
+/**
+ * zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s)
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @start_addr: address of memory segment
+ * @total_length: length of memory segment
+ *
+ * Alignment and length of the segment determine how many SBALEs are needed
+ * for the memory segment.
+ */
+static inline int
+zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+			     void *start_addr, unsigned long total_length)
+{
+	unsigned long remaining, length;
+	void *addr;
+
+	/* split segment up heeding page boundaries */
+	for (addr = start_addr, remaining = total_length; remaining > 0;
+	     addr += length, remaining -= length) {
+		/* get next free SBALE for new piece */
+		if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) {
+			/* no SBALE left, clean up and leave */
+			zfcp_qdio_sbals_wipe(fsf_req);
+			return -EINVAL;
+		}
+		/* calculate length of new piece */
+		length = min(remaining,
+			     (PAGE_SIZE - ((unsigned long) addr &
+					   (PAGE_SIZE - 1))));
+		/* fill current SBALE with calculated piece */
+		zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length);
+	}
+	return total_length;
+}
+
+
+/**
+ * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @sg: scatter-gather list
+ * @sg_count: number of elements in scatter-gather list
+ * @max_sbals: upper bound for number of SBALs to be used
+ */
+inline int
+zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+                        struct scatterlist *sg,	int sg_count, int max_sbals)
+{
+	int sg_index;
+	struct scatterlist *sg_segment;
+	int retval;
+	volatile struct qdio_buffer_element *sbale;
+	int bytes = 0;
+
+	/* figure out last allowed SBAL */
+	zfcp_qdio_sbal_limit(fsf_req, max_sbals);
+
+	/* set storage-block type for current SBAL */
+	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+	sbale->flags |= sbtype;
+
+	/* process all segements of scatter-gather list */
+	for (sg_index = 0, sg_segment = sg, bytes = 0;
+	     sg_index < sg_count;
+	     sg_index++, sg_segment++) {
+		retval = zfcp_qdio_sbals_from_segment(
+				fsf_req,
+				sbtype,
+				zfcp_sg_to_address(sg_segment),
+				sg_segment->length);
+		if (retval < 0) {
+			bytes = retval;
+			goto out;
+		} else
+                        bytes += retval;
+	}
+	/* assume that no other SBALEs are to follow in the same SBAL */
+	sbale = zfcp_qdio_sbale_curr(fsf_req);
+	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+
+out:
+#ifdef ZFCP_STAT_REQSIZES
+	if (sbtype == SBAL_FLAGS0_TYPE_READ) {
+		zfcp_statistics_inc(&zfcp_data.read_sguse_head, sg_count);
+		zfcp_statistics_inc(&zfcp_data.read_req_head, bytes);
+	} else	{
+		zfcp_statistics_inc(&zfcp_data.write_sguse_head, sg_count);
+        	zfcp_statistics_inc(&zfcp_data.write_req_head, bytes);
+	}
+#endif
+
+	return bytes;
+}
+
+
+/**
+ * zfcp_qdio_sbals_from_buffer - fill SBALs from buffer
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @buffer: data buffer
+ * @length: length of buffer
+ * @max_sbals: upper bound for number of SBALs to be used
+ */
+static inline int
+zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+			    void *buffer, unsigned long length, int max_sbals)
+{
+	struct scatterlist sg_segment;
+
+	zfcp_address_to_sg(buffer, &sg_segment);
+	sg_segment.length = length;
+
+	return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1,
+                                       max_sbals);
+}
+
+
+/**
+ * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command
+ * @fsf_req: request to be processed
+ * @sbtype: SBALE flags
+ * @scsi_cmnd: either scatter-gather list or buffer contained herein is used
+ *	to fill SBALs
+ */
+inline int
+zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
+			      unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
+{
+	if (scsi_cmnd->use_sg) {
+		return zfcp_qdio_sbals_from_sg(fsf_req,	sbtype,
+                                               (struct scatterlist *)
+                                               scsi_cmnd->request_buffer,
+                                               scsi_cmnd->use_sg,
+                                               ZFCP_MAX_SBALS_PER_REQ);
+	} else {
+                return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype,
+                                                   scsi_cmnd->request_buffer,
+                                                   scsi_cmnd->request_bufflen,
+                                                   ZFCP_MAX_SBALS_PER_REQ);
+	}
+}
+
+/**
+ * zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed
+ */
 int
 zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue,
 			struct zfcp_fsf_req *fsf_req)
 {
 	int new_distance_from_int;
 	int pci_pos;
+	volatile struct qdio_buffer_element *sbale;
 
 	new_distance_from_int = req_queue->distance_from_int +
-				fsf_req->sbal_count;
+                fsf_req->sbal_number;
+
 	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;
+                pci_pos  = fsf_req->sbal_first;
+		pci_pos += fsf_req->sbal_number;
 		pci_pos -= new_distance_from_int;
 		pci_pos -= 1;
 		pci_pos %= QDIO_MAX_BUFFERS_PER_Q;
-		req_queue->buffer[pci_pos]->element[0].flags |= SBAL_FLAGS0_PCI;
-		ZFCP_LOG_TRACE("Setting PCI flag at pos %d\n", pci_pos);
+		sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0);
+		sbale->flags |= SBAL_FLAGS0_PCI;
 	}
 	return new_distance_from_int;
 }
@@ -570,4 +910,3 @@ zfcp_qdio_zero_sbals(struct qdio_buffer 
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_scsi.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_scsi.c
--- 25/drivers/s390/scsi/zfcp_scsi.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_scsi.c	Fri Feb 20 16:00:58 2004
@@ -4,11 +4,12 @@
  * 
  * FCP adapter driver for IBM eServer zSeries 
  * 
- * Copyright 2002 IBM Corporation 
+ * (C) Copyright IBM Corp. 2002, 2004
+ *
  * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
  *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
- *            Aron Zeh <arzeh@de.ibm.com> 
- *            Wolfgang Taphorn <taphorn@de.ibm.com> 
+ *            Aron Zeh
+ *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com> 
  *            Heiko Carstens <heiko.carstens@de.ibm.com> 
  * 
@@ -28,9 +29,9 @@
  */
 
 #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.42 $"
+#define ZFCP_SCSI_REVISION "$Revision: 1.52 $"
 
 #include <linux/blkdev.h>
 
@@ -39,24 +40,14 @@
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
 static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
 static int zfcp_scsi_slave_configure(struct scsi_device *sdp);
-static int zfcp_scsi_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int zfcp_scsi_eh_abort_handler(Scsi_Cmnd *);
-static int zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd *);
-static int zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd *);
-static int zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd *);
+static int zfcp_scsi_queuecommand(struct scsi_cmnd *,
+				  void (*done) (struct scsi_cmnd *));
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
 static int zfcp_task_management_function(struct zfcp_unit *, u8);
 
-static int zfcp_create_sbales_from_segment(unsigned long, int, int *,
-					   int, int, int *, int *, int,
-					   int, struct qdio_buffer **,
-					   char);
-
-static int zfcp_create_sbale(unsigned long, int, int *, int, int, int *,
-			     int, int, int *, struct qdio_buffer **,
-			     char);
-
-static struct zfcp_unit *zfcp_scsi_determine_unit(struct zfcp_adapter *,
-						  Scsi_Cmnd *);
 static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, int, int);
 
 static struct device_attribute *zfcp_sysfs_sdev_attrs[];
@@ -225,59 +216,7 @@ zfcp_scsi_slave_destroy(struct scsi_devi
 	}
 }
 
-void
-zfcp_scsi_block_requests(struct Scsi_Host *shpnt)
-{
-	scsi_block_requests(shpnt);
-	/* This is still somewhat racy but the best I could imagine */
-	do {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(ZFCP_SCSI_HOST_FLUSH_TIMEOUT);
-
-	} while (shpnt->host_busy || shpnt->eh_active);
-}
-
 /* 
- * Tries to associate a zfcp unit with the scsi device.
- *
- * returns:       unit pointer   if unit is found
- *                NULL           otherwise
- */
-struct zfcp_unit *
-zfcp_scsi_determine_unit(struct zfcp_adapter *adapter, Scsi_Cmnd * scpnt)
-{
-	struct zfcp_unit *unit;
-
-	/*
-	 * figure out target device
-	 * (stored there by zfcp_scsi_slave_alloc)
-	 * ATTENTION: assumes hostdata initialized to NULL by
-	 * mid layer (see scsi_scan.c)
-	 */
-	unit = (struct zfcp_unit *) scpnt->device->hostdata;
-	if (!unit) {
-		ZFCP_LOG_DEBUG("logical unit (%i %i %i %i) not configured\n",
-			       scpnt->device->host->host_no,
-			       scpnt->device->channel,
-			       scpnt->device->id, scpnt->device->lun);
-		/*
-		 * must fake SCSI command execution and scsi_done
-		 * callback for non-configured logical unit
-		 */
-		/* return this as long as we are unable to process requests */
-		set_host_byte(&scpnt->result, DID_NO_CONNECT);
-		zfcp_cmd_dbf_event_scsi("notconf", scpnt);
-		scpnt->scsi_done(scpnt);
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 2, "nc_done:");
-		debug_event(adapter->req_dbf, 2, &scpnt,
-			    sizeof (unsigned long));
-#endif				/* ZFCP_DEBUG_REQUESTS */
-	}
-	return unit;
-}
-
-/*
  * called from scsi midlayer to allow finetuning of a device.
  */
 static int
@@ -290,124 +229,143 @@ zfcp_scsi_slave_configure(struct scsi_de
 	return 0;
 }
 
-/* Complete a command immediately handing back DID_ERROR */
+/**
+ * zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function
+ * @scpnt: pointer to struct scsi_cmnd where result is set
+ * @result: result to be set in scpnt (e.g. DID_ERROR)
+ */
 static void
-zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
-			    struct zfcp_adapter *adapter,
-			    struct zfcp_unit *unit)
-{
-	/* Always pass through to upper layer */
-	scpnt->retries = scpnt->allowed - 1;
-	set_host_byte(&scpnt->result, DID_ERROR);
-	zfcp_cmd_dbf_event_scsi("stopping", scpnt);
+zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
+{
+	set_host_byte(&scpnt->result, result);
+	zfcp_cmd_dbf_event_scsi("failing", scpnt);
 	/* return directly */
 	scpnt->scsi_done(scpnt);
-	if (adapter && unit) {
-		ZFCP_LOG_INFO("Stopping SCSI IO on the unit with FCP LUN 0x%Lx "
-			      "connected to the port with WWPN 0x%Lx at the "
-			      "adapter %s.\n",
-			      unit->fcp_lun,
-			      unit->port->wwpn,
-			      zfcp_get_busid_by_adapter(adapter));
-#ifdef ZFCP_DEBUG_REQUESTS
-		debug_text_event(adapter->req_dbf, 2, "de_done:");
-		debug_event(adapter->req_dbf, 2, &scpnt,
-			    sizeof (unsigned long));
-#endif				/* ZFCP_DEBUG_REQUESTS */
-	} else {
-		ZFCP_LOG_INFO("There is no adapter registered in the zfcp "
-			      "module for the SCSI host with hostnumber %d. "
-			      "Stopping IO.\n", scpnt->device->host->host_no);
-	}
 }
 
-/*
- * function:	zfcp_scsi_queuecommand
- *
- * purpose:	enqueues a SCSI command to the specified target device
- *
- * note:        The scsi_done midlayer function may be called directly from
- *              within queuecommand provided queuecommand returns with
- *              success (0).
- *              If it fails, it is expected that the command could not be sent
- *              and is still available for processing.
- *              As we ensure that queuecommand never fails, we have the choice 
- *              to call done directly wherever we please.
- *              Thus, any kind of send errors other than those indicating
- *              'infinite' retries will be reported directly.
- *              Retry requests are put into a list to be processed under timer 
- *              control once in a while to allow for other operations to
- *              complete in the meantime.
+/**
+ * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and
+ *	zfcp_scsi_command_sync
+ * @adapter: adapter for where scsi command is issued
+ * @unit: unit to which scsi command is sent
+ * @scpnt: scsi command to be sent
  *
- * returns:	0 - success, SCSI command enqueued
- *		!0 - failure, note that we never allow this to happen as the 
- *              SCSI stack would block indefinitely should a non-zero return
- *              value be reported if there are no outstanding commands
- *              (as in when the queues are down)
+ * Note: In scsi_done function must be set in scpnt.
  */
 int
-zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
+zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
+			struct scsi_cmnd *scpnt)
 {
+	int tmp;
 	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 */
-	scpnt->scsi_done = done;
-	/*
-	 * figure out adapter
-	 * (previously stored there by the driver when
-	 * the adapter was registered)
-	 */
-	adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
-	/* NULL when the adapter was removed from the zfcp list */
-	if (unlikely(adapter == NULL)) {
-		zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL);
-		goto out;
-	}
 
-	unit = zfcp_scsi_determine_unit(adapter, scpnt);
-	if (unlikely(unit == NULL))
+	BUG_ON((adapter == NULL) || (adapter != unit->port->adapter));
+	BUG_ON(scpnt->scsi_done == NULL);
+
+	if (unlikely(NULL == unit)) {
+		zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT);
 		goto out;
+	}
 
 	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);
+		ZFCP_LOG_DEBUG("Stopping SCSI IO on the unit with "
+			       "FCP LUN 0x%Lx connected to the port "
+			       "with WWPN 0x%Lx at the adapter %s.\n",
+			       unit->fcp_lun,
+			       unit->port->wwpn,
+			       zfcp_get_busid_by_adapter(adapter));
+		zfcp_scsi_command_fail(scpnt, DID_ERROR);
 		goto out;
 	}
+
 	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),
+			       zfcp_get_busid_by_unit(unit),
 			       unit->fcp_lun, unit->port->wwpn);
 		retval = SCSI_MLQUEUE_DEVICE_BUSY;
 		goto out;
 	}
 
-	temp_ret = zfcp_fsf_send_fcp_command_task(adapter,
-						  unit,
-						  scpnt, ZFCP_REQ_AUTO_CLEANUP);
+	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt,
+					     ZFCP_REQ_AUTO_CLEANUP);
 
-	if (unlikely(temp_ret < 0)) {
+	if (unlikely(tmp < 0)) {
 		ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n");
 		retval = SCSI_MLQUEUE_HOST_BUSY;
 	} else {
+
 #ifdef ZFCP_DEBUG_REQUESTS
 		debug_text_event(adapter->req_dbf, 3, "q_scpnt");
 		debug_event(adapter->req_dbf, 3, &scpnt,
 			    sizeof (unsigned long));
 #endif				/* ZFCP_DEBUG_REQUESTS */
 	}
- out:
+
+out:
 	return retval;
 }
 
+void
+zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
+{
+	struct completion *wait = (struct completion *) scpnt->SCp.ptr;
+	complete(wait);
+}
+
+
+/**
+ * zfcp_scsi_command_sync - send a SCSI command and wait for completion
+ * returns 0, errors are indicated by scsi_cmnd->result
+ */
+int
+zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt)
+{
+	DECLARE_COMPLETION(wait);
+
+	scpnt->SCp.ptr = (void *) &wait;  /* silent re-use */
+	scpnt->done = zfcp_scsi_command_sync_handler;
+        zfcp_scsi_command_async(unit->port->adapter, unit, scpnt);
+	wait_for_completion(&wait);
+
+	return 0;
+}
+
+/*
+ * function:	zfcp_scsi_queuecommand
+ *
+ * purpose:	enqueues a SCSI command to the specified target device
+ *
+ * returns:	0 - success, SCSI command enqueued
+ *		!0 - failure
+ */
+int
+zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
+		       void (*done) (struct scsi_cmnd *))
+{
+	struct zfcp_unit *unit;
+	struct zfcp_adapter *adapter;
+
+	/* reset the status for this request */
+	scpnt->result = 0;
+	/* save address of mid layer call back function */
+	scpnt->scsi_done = done;
+
+	/*
+	 * figure out adapter and target device
+	 * (stored there by zfcp_scsi_slave_alloc)
+	 */
+	adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+	unit = (struct zfcp_unit *) scpnt->device->hostdata;
+
+	return zfcp_scsi_command_async(adapter, unit, scpnt);
+}
+
 /*
  * function:    zfcp_unit_lookup
  *
@@ -456,22 +414,18 @@ zfcp_unit_lookup(struct zfcp_adapter *ad
  *		FAILED	- otherwise
  */
 int
-zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 {
 	int retval = SUCCESS;
 	struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
-	struct zfcp_adapter *adapter;
-	struct zfcp_unit *unit;
-	struct zfcp_port *port;
-	struct Scsi_Host *scsi_host;
+	struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+	struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
+	struct zfcp_port *port = unit->port;
+	struct Scsi_Host *scsi_host = scpnt->device->host;
 	union zfcp_req_data *req_data = NULL;
 	unsigned long flags;
 	u32 status = 0;
 
-	adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
-	scsi_host = scpnt->device->host;
-	unit = (struct zfcp_unit *) scpnt->device->hostdata;
-	port = unit->port;
 
 #ifdef ZFCP_DEBUG_ABORTS
 	/* the components of a abort_dbf record (fixed size record) */
@@ -657,7 +611,7 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * s
  * returns:
  */
 int
-zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 {
 	int retval;
 	struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
@@ -764,7 +718,7 @@ zfcp_task_management_function(struct zfc
  * returns:
  */
 int
-zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
 {
 	int retval = 0;
 	struct zfcp_unit *unit;
@@ -793,7 +747,7 @@ zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd
  * returns:
  */
 int
-zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd * scpnt)
+zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
 	int retval = 0;
 	struct zfcp_unit *unit;
@@ -887,332 +841,6 @@ zfcp_adapter_scsi_unregister(struct zfcp
 }
 
 
-/**
- * zfcp_create_sbales_from_segment - creates SBALEs
- * @addr:          begin of this buffer segment
- * @length_seg:	   length of this buffer segment
- * @length_total:  total length of buffer
- * @length_min:    roll back if generated buffer smaller than this
- * @length_max:	   sum of all SBALEs (count) not larger than this
- * @buffer_index:  position of current BUFFER
- * @buffere_index: position of current BUFFERE
- * @buffer_first:  first BUFFER used for this buffer
- * @buffer_last:   last BUFFER in request queue allowed
- * @buffer:        begin of SBAL array of request queue
- * @sbtype:        storage-block type
- */
-static int
-zfcp_create_sbales_from_segment(unsigned long addr, int length_seg,
-				int *length_total, int length_min,
-				int length_max, int *buffer_index,
-				int *buffere_index, int buffer_first,
-				int buffer_last, struct qdio_buffer *buffer[],
-				char sbtype)
-{
-	int retval = 0;
-	int length = 0;
-
-	ZFCP_LOG_TRACE
-	    ("SCSI data buffer segment with %i bytes from 0x%lx to 0x%lx\n",
-	     length_seg, addr, (addr + length_seg) - 1);
-
-	if (!length_seg)
-		goto out;
-
-	if (addr & (PAGE_SIZE - 1)) {
-		length =
-		    min((int) (PAGE_SIZE - (addr & (PAGE_SIZE - 1))),
-			length_seg);
-		ZFCP_LOG_TRACE
-		    ("address 0x%lx not on page boundary, length=0x%x\n",
-		     (unsigned long) addr, length);
-		retval =
-		    zfcp_create_sbale(addr, length, length_total, length_min,
-				      length_max, buffer_index, buffer_first,
-				      buffer_last, buffere_index, buffer,
-				      sbtype);
-		if (retval) {
-			/* no resources */
-			goto out;
-		}
-		addr += length;
-		length = length_seg - length;
-	} else
-		length = length_seg;
-
-	while (length > 0) {
-		retval = zfcp_create_sbale(addr, min((int) PAGE_SIZE, length),
-					   length_total, length_min, length_max,
-					   buffer_index, buffer_first,
-					   buffer_last, buffere_index, buffer,
-					   sbtype);
-		if (*buffere_index > ZFCP_LAST_SBALE_PER_SBAL)
-			ZFCP_LOG_NORMAL("bug: Filling output buffers with SCSI "
-					"data failed. Index ran out of bounds. "
-					"(debug info %d)\n", *buffere_index);
-		if (retval) {
-			/* no resources */
-			goto out;
-		}
-		length -= PAGE_SIZE;
-		addr += PAGE_SIZE;
-	}
- out:
-	return retval;
-}
-
-/**
- * zfcp_create_sbale - creates a single SBALE
- * @addr:          begin of this buffer segment
- * @length:        length of this buffer segment
- * @length_total:  total length of buffer
- * @length_min:    roll back if generated buffer smaller than this
- * @length_max:    sum of all SBALEs (count) not larger than this
- * @buffer_index:  position of current BUFFER
- * @buffer_first:  first BUFFER used for this buffer
- * @buffer_last:   last BUFFER allowed for this buffer
- * @buffere_index: position of current BUFFERE of current BUFFER
- * @buffer:        begin of SBAL array of request queue
- * @sbtype:        storage-block type
- */
-static int
-zfcp_create_sbale(unsigned long addr, int length, int *length_total,
-		  int length_min, int length_max, int *buffer_index,
-		  int buffer_first, int buffer_last, int *buffere_index,
-		  struct qdio_buffer *buffer[], char sbtype)
-{
-	int retval = 0;
-	int length_real, residual;
-	int buffers_used;
-
-	volatile struct qdio_buffer_element *buffere =
-	    &(buffer[*buffer_index]->element[*buffere_index]);
-
-	/* check whether we hit the limit */
-	residual = length_max - *length_total;
-	if (residual == 0) {
-		ZFCP_LOG_TRACE("skip remaining %i bytes since length_max hit\n",
-			       length);
-		goto out;
-	}
-	length_real = min(length, residual);
-
-	/*
-	 * figure out next BUFFERE
-	 * (first BUFFERE of first BUFFER is skipped - 
-	 * this is ok since it is reserved for the QTCB)
-	 */
-	if (*buffere_index == ZFCP_LAST_SBALE_PER_SBAL) {
-		/* last BUFFERE in this BUFFER */
-		buffere->flags |= SBAL_FLAGS_LAST_ENTRY;
-		/* need further BUFFER */
-		if (*buffer_index == buffer_last) {
-			/* queue full or last allowed BUFFER */
-			buffers_used = (buffer_last - buffer_first) + 1;
-			/* avoid modulo operation on negative value */
-			buffers_used += QDIO_MAX_BUFFERS_PER_Q;
-			buffers_used %= QDIO_MAX_BUFFERS_PER_Q;
-			ZFCP_LOG_DEBUG("reached limit of number of BUFFERs "
-				       "allowed for this request\n");
-			/* FIXME (design) - This check is wrong and enforces the
-			 * use of one SBALE less than possible 
-			 */
-			if ((*length_total < length_min)
-			    || (buffers_used < ZFCP_MAX_SBALS_PER_REQ)) {
-				ZFCP_LOG_DEBUG("Rolling back SCSI command as "
-					       "there are insufficient buffers "
-					       "to cover the minimum required "
-					       "amount of data\n");
-				/*
-				 * roll back complete list of BUFFERs generated
-				 * from the scatter-gather list associated
-				 * with this SCSI command
-				 */
-				zfcp_qdio_zero_sbals(buffer,
-						     buffer_first,
-						     buffers_used);
-				*length_total = 0;
-			} else {
-				/* DEBUG */
-				ZFCP_LOG_NORMAL("Not enough buffers available. "
-						"Can only transfer %i bytes of "
-						"data\n",
-						*length_total);
-			}
-			retval = -ENOMEM;
-			goto out;
-		} else {	/* *buffer_index != buffer_last */
-			/* chain BUFFERs */
-			*buffere_index = 0;
-			buffere =
-			    &(buffer[*buffer_index]->element[*buffere_index]);
-			buffere->flags |= SBAL_FLAGS0_MORE_SBALS;
-			(*buffer_index)++;
-			*buffer_index %= QDIO_MAX_BUFFERS_PER_Q;
-			buffere =
-			    &(buffer[*buffer_index]->element[*buffere_index]);
-			buffere->flags |= sbtype;
-			ZFCP_LOG_DEBUG
-			    ("Chaining previous BUFFER %i to BUFFER %i\n",
-			     ((*buffer_index !=
-			       0) ? *buffer_index - 1 : QDIO_MAX_BUFFERS_PER_Q -
-			      1), *buffer_index);
-		}
-	} else { /* *buffere_index != (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) */
-		(*buffere_index)++;
-		buffere = &(buffer[*buffer_index]->element[*buffere_index]);
-	}
-
-	/* ok, found a place for this piece, put it there */
-	buffere->addr = (void *) addr;
-	buffere->length = length_real;
-
-#ifdef ZFCP_STAT_REQSIZES
-	if (sbtype == SBAL_FLAGS0_TYPE_READ)
-		zfcp_statistics_inc(&zfcp_data.read_sg_head, length_real);
-	else
-		zfcp_statistics_inc(&zfcp_data.write_sg_head, length_real);
-#endif
-
-	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) addr, length_real);
-	ZFCP_LOG_TRACE("BUFFER no %i (0x%lx) BUFFERE no %i (0x%lx): BUFFERE "
-		       "data addr 0x%lx, BUFFERE length %i, BUFFER type %i\n",
-		       *buffer_index,
-		       (unsigned long) &buffer[*buffer_index], *buffere_index,
-		       (unsigned long) buffere, addr, length_real, sbtype);
-	*length_total += length_real;
- out:
-	return retval;
-}
-
-/*
- * function:    zfcp_create_sbals_from_sg
- *
- * purpose:	walks through scatter-gather list of specified SCSI command
- *		and creates a corresponding list of SBALs
- *
- * returns:	size of generated buffer in bytes 
- *
- * context:	
- */
-int
-zfcp_create_sbals_from_sg(struct zfcp_fsf_req *fsf_req, Scsi_Cmnd * scpnt,
-			  char sbtype,	/* storage-block type */
-			  int length_min, /* roll back if generated buffer */
-			  int buffer_max) /* max numbers of BUFFERs */
-{
-	int length_total = 0;
-	int buffer_index = 0;
-	int buffer_last = 0;
-	int buffere_index = 1;	/* elements 0 and 1 are req-id and qtcb */
-	volatile struct qdio_buffer_element *buffere = NULL;
-	struct zfcp_qdio_queue *req_q = NULL;
-	int length_max = scpnt->request_bufflen;
-
-	req_q = &fsf_req->adapter->request_queue;
-
-	buffer_index = req_q->free_index;
-	buffer_last = req_q->free_index +
-	    min(buffer_max, atomic_read(&req_q->free_count)) - 1;
-	buffer_last %= QDIO_MAX_BUFFERS_PER_Q;
-
-	ZFCP_LOG_TRACE
-	    ("total SCSI data buffer size is (scpnt->request_bufflen) %i\n",
-	     scpnt->request_bufflen);
-	ZFCP_LOG_TRACE
-	    ("BUFFERs from (buffer_index)%i to (buffer_last)%i available\n",
-	     buffer_index, buffer_last);
-	ZFCP_LOG_TRACE("buffer_max=%d, req_q->free_count=%d\n", buffer_max,
-		       atomic_read(&req_q->free_count));
-
-	if (scpnt->use_sg) {
-		int sg_index;
-		struct scatterlist *list
-		    = (struct scatterlist *) scpnt->request_buffer;
-
-		ZFCP_LOG_DEBUG("%i (scpnt->use_sg) scatter-gather segments\n",
-			       scpnt->use_sg);
-
-		//                length_max+=0x2100;
-
-#ifdef ZFCP_STAT_REQSIZES
-		if (sbtype == SBAL_FLAGS0_TYPE_READ)
-			zfcp_statistics_inc(&zfcp_data.read_sguse_head,
-					    scpnt->use_sg);
-		else
-			zfcp_statistics_inc(&zfcp_data.write_sguse_head,
-					    scpnt->use_sg);
-#endif
-
-		for (sg_index = 0; sg_index < scpnt->use_sg; sg_index++, list++)
-		{
-			if (zfcp_create_sbales_from_segment(
-				    (page_to_pfn (list->page) << PAGE_SHIFT) +
-				    list->offset,
-				    list->length,
-				    &length_total,
-				    length_min,
-				    length_max,
-				    &buffer_index,
-				    &buffere_index,
-				    req_q->free_index,
-				    buffer_last,
-				    req_q->buffer,
-				    sbtype))
-				break;
-		}
-	} else {
-		ZFCP_LOG_DEBUG("no scatter-gather list\n");
-#ifdef ZFCP_STAT_REQSIZES
-		if (sbtype == SBAL_FLAGS0_TYPE_READ)
-			zfcp_statistics_inc(&zfcp_data.read_sguse_head, 1);
-		else
-			zfcp_statistics_inc(&zfcp_data.write_sguse_head, 1);
-#endif
-		zfcp_create_sbales_from_segment(
-			(unsigned long) scpnt->request_buffer,
-			scpnt->request_bufflen,
-			&length_total,
-			length_min,
-			length_max,
-			&buffer_index,
-			&buffere_index,
-			req_q->free_index,
-			buffer_last,
-			req_q->buffer,
-			sbtype);
-	}
-
-	fsf_req->sbal_index = req_q->free_index;
-
-	if (buffer_index >= fsf_req->sbal_index) {
-		fsf_req->sbal_count = (buffer_index - fsf_req->sbal_index) + 1;
-	} else {
-		fsf_req->sbal_count =
-		    (QDIO_MAX_BUFFERS_PER_Q - fsf_req->sbal_index) +
-		    buffer_index + 1;
-	}
-	/* HACK */
-	if ((scpnt->request_bufflen != 0) && (length_total == 0))
-		goto out;
-
-#ifdef ZFCP_STAT_REQSIZES
-	if (sbtype == SBAL_FLAGS0_TYPE_READ)
-		zfcp_statistics_inc(&zfcp_data.read_req_head, length_total);
-	else
-		zfcp_statistics_inc(&zfcp_data.write_req_head, length_total);
-#endif
-
-	buffere = &(req_q->buffer[buffer_index]->element[buffere_index]);
-	buffere->flags |= SBAL_FLAGS_LAST_ENTRY;
- out:
-	ZFCP_LOG_DEBUG("%i BUFFER(s) from %i to %i needed\n",
-		       fsf_req->sbal_count, fsf_req->sbal_index, buffer_index);
-	ZFCP_LOG_TRACE("total QDIO data buffer size is %i\n", length_total);
-
-	return length_total;
-}
-
 void
 zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
 {
@@ -1293,4 +921,3 @@ static struct device_attribute *zfcp_sys
 };
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_sysfs_adapter.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_adapter.c
--- 25/drivers/s390/scsi/zfcp_sysfs_adapter.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_adapter.c	Fri Feb 20 16:00:58 2004
@@ -5,7 +5,8 @@
  *
  * sysfs adapter related routines
  *
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
  * Authors:
  *      Martin Peschke <mpeschke@de.ibm.com>
  *	Heiko Carstens <heiko.carstens@de.ibm.com>
@@ -25,14 +26,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.26 $"
+#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.30 $"
 
 #include <asm/ccwdev.h>
 #include "zfcp_ext.h"
 #include "zfcp_def.h"
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_CONFIG
 
 static const char fc_topologies[5][25] = {
 	{"<error>"},
@@ -66,12 +66,15 @@ ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x
 ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn);
 ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn);
 ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id);
-ZFCP_DEFINE_ADAPTER_ATTR(hw_version, "0x%04x\n", adapter->hydra_version);
+ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
 ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
 ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed);
 ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class);
 ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
 			 fc_topologies[adapter->fc_topology]);
+ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
+			 adapter->hardware_version);
+ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number);
 
 /**
  * zfcp_sysfs_adapter_in_recovery_show - recovery state of adapter
@@ -259,11 +262,6 @@ zfcp_sysfs_adapter_failed_store(struct d
 		goto out;
 	}
 
-	/* restart error recovery only if adapter is online */
-	if (adapter->ccw_device->online != 1) {
-		retval = -ENXIO;
-		goto out;
-	}
 	zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
 				       ZFCP_SET);
 	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
@@ -304,13 +302,15 @@ static struct attribute *zfcp_adapter_at
 	&dev_attr_wwnn.attr,
 	&dev_attr_wwpn.attr,
 	&dev_attr_s_id.attr,
-	&dev_attr_hw_version.attr,
+	&dev_attr_card_version.attr,
 	&dev_attr_lic_version.attr,
 	&dev_attr_fc_link_speed.attr,
 	&dev_attr_fc_service_class.attr,
 	&dev_attr_fc_topology.attr,
 	&dev_attr_scsi_host_no.attr,
 	&dev_attr_status.attr,
+	&dev_attr_hardware_version.attr,
+	&dev_attr_serial_number.attr,
 	NULL
 };
 
@@ -343,4 +343,3 @@ zfcp_sysfs_adapter_remove_files(struct d
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_sysfs_driver.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_driver.c
--- 25/drivers/s390/scsi/zfcp_sysfs_driver.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_driver.c	Fri Feb 20 16:00:58 2004
@@ -5,7 +5,8 @@
  *
  * sysfs driver related routines
  *
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
  * Authors:
  *      Martin Peschke <mpeschke@de.ibm.com>
  *	Heiko Carstens <heiko.carstens@de.ibm.com>
@@ -25,14 +26,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.8 $"
+#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.12 $"
 
 #include <asm/ccwdev.h>
 #include "zfcp_ext.h"
 #include "zfcp_def.h"
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_CONFIG
 
 /**
  * ZFCP_DEFINE_DRIVER_ATTR - define for all loglevels sysfs attributes
@@ -67,7 +67,8 @@ static ssize_t zfcp_sysfs_loglevel_##_na
 static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev,  \
 						  char *buf)                  \
 {                                                                             \
-	return sprintf(buf,"%d\n", ZFCP_LOG_VALUE(ZFCP_LOG_AREA_##_define));  \
+	return sprintf(buf,"%d\n",				              \
+		       ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define));          \
 }                                                                             \
                                                                               \
 static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO,                       \
@@ -83,6 +84,14 @@ ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO);
 ZFCP_DEFINE_DRIVER_ATTR(erp, ERP);
 ZFCP_DEFINE_DRIVER_ATTR(fc, FC);
 
+static ssize_t zfcp_sysfs_version_show(struct device_driver *dev,
+					      char *buf)
+{
+	return sprintf(buf, "%s\n", ZFCP_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, zfcp_sysfs_version_show, NULL);
+
 static struct attribute *zfcp_driver_attrs[] = {
 	&driver_attr_loglevel_other.attr,
 	&driver_attr_loglevel_scsi.attr,
@@ -92,6 +101,7 @@ static struct attribute *zfcp_driver_att
 	&driver_attr_loglevel_qdio.attr,
 	&driver_attr_loglevel_erp.attr,
 	&driver_attr_loglevel_fc.attr,
+	&driver_attr_version.attr,
 	NULL
 };
 
@@ -124,4 +134,3 @@ zfcp_sysfs_driver_remove_files(struct de
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_sysfs_port.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_port.c
--- 25/drivers/s390/scsi/zfcp_sysfs_port.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_port.c	Fri Feb 20 16:00:58 2004
@@ -5,7 +5,8 @@
  *
  * sysfs port related routines
  *
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
  * Authors:
  *      Martin Peschke <mpeschke@de.ibm.com>
  *	Heiko Carstens <heiko.carstens@de.ibm.com>
@@ -25,7 +26,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.32 $"
+#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.37 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -34,7 +35,6 @@
 #include "zfcp_def.h"
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_CONFIG
 
 /**
  * zfcp_sysfs_port_release - gets called when a struct device port is released
@@ -209,11 +209,6 @@ zfcp_sysfs_port_failed_store(struct devi
 		goto out;
 	}
 
-	/* restart error recovery only if adapter is online */
-	if (port->adapter->ccw_device->online != 1) {
-		retval = -ENXIO;
-		goto out;
-	}
 	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);
@@ -268,6 +263,10 @@ zfcp_sysfs_port_in_recovery_show(struct 
 static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_port_in_recovery_show,
 		   NULL);
 
+/**
+ * zfcp_port_common_attrs
+ * sysfs attributes that are common for all kind of fc ports.
+ */
 static struct attribute *zfcp_port_common_attrs[] = {
 	&dev_attr_failed.attr,
 	&dev_attr_in_recovery.attr,
@@ -281,6 +280,10 @@ static struct attribute_group zfcp_port_
 	.attrs = zfcp_port_common_attrs,
 };
 
+/**
+ * zfcp_port_no_ns_attrs
+ * sysfs attributes not to be used for nameserver ports.
+ */
 static struct attribute *zfcp_port_no_ns_attrs[] = {
 	&dev_attr_unit_add.attr,
 	&dev_attr_unit_remove.attr,
@@ -330,4 +333,3 @@ zfcp_sysfs_port_remove_files(struct devi
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
diff -puN drivers/s390/scsi/zfcp_sysfs_unit.c~s390-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_unit.c
--- 25/drivers/s390/scsi/zfcp_sysfs_unit.c~s390-zfcp-host-adapter	Fri Feb 20 16:00:58 2004
+++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_unit.c	Fri Feb 20 16:00:58 2004
@@ -5,7 +5,8 @@
  *
  * sysfs unit related routines
  *
- * Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
+ * (C) Copyright IBM Corp. 2003, 2004
+ *
  * Authors:
  *      Martin Peschke <mpeschke@de.ibm.com>
  *	Heiko Carstens <heiko.carstens@de.ibm.com>
@@ -25,7 +26,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.19 $"
+#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.23 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -34,7 +35,6 @@
 #include "zfcp_def.h"
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
-#define ZFCP_LOG_AREA_PREFIX            ZFCP_LOG_AREA_PREFIX_CONFIG
 
 /**
  * zfcp_sysfs_unit_release - gets called when a struct device unit is released
@@ -104,13 +104,9 @@ zfcp_sysfs_unit_failed_store(struct devi
 		goto out;
 	}
 
-	/* restart error recovery only if adapter is online */
-	if (unit->port->adapter->ccw_device->online != 1) {
-		retval = -ENXIO;
-		goto out;
-	}
 	zfcp_erp_modify_unit_status(unit, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
 	zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
+	zfcp_erp_wait(unit->port->adapter);
  out:
 	up(&zfcp_data.config_sema);
 	return retval ? retval : count;
@@ -199,4 +195,3 @@ zfcp_sysfs_unit_remove_files(struct devi
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX

_