]> git.hungrycats.org Git - linux/commitdiff
[PATCH] s390: zfcp host adapter
authorAndrew Morton <akpm@osdl.org>
Thu, 26 Feb 2004 00:20:50 +0000 (16:20 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 26 Feb 2004 00:20:50 +0000 (16:20 -0800)
From: Martin Schwidefsky <schwidefsky@de.ibm.com>

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

14 files changed:
Documentation/ioctl-number.txt
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs_adapter.c
drivers/s390/scsi/zfcp_sysfs_driver.c
drivers/s390/scsi/zfcp_sysfs_port.c
drivers/s390/scsi/zfcp_sysfs_unit.c

index 01c0d047cd53d64de821cc47a676032687f9fd33..1af5712b8f9a08d086dd9ead66ec0828c0e8e259 100644 (file)
@@ -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>
index d34923a5b44a0396569f590872122a090bafc8ff..5315aa980f6398b209fb1c6996fbb0056f0570d3 100644 (file)
@@ -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 list_head *);
 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, struct zfcp_fsf_req *fsf_req,
 {
 #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, struct zfcp_fsf_req *fsf_req,
                            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, struct zfcp_fsf_req *fsf_req,
 #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, Scsi_Cmnd * scsi_cmnd)
        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_block *notifier, unsigned long code,
        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 *size)
 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 *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 *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 *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 *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 *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_adapter *adapter)
 }
 
 #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_adapter *adapter,
                                     "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_req *fsf_req)
                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;
+        if ((gid_pn->ct.pool != 0)) {
+               mempool_free(gid_pn, gid_pn->ct.pool);
+        } else {
+                kfree(gid_pn);
        }
 
-       /* 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;
-       }
+       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;
-
-       if (fc_ct_iu_resp->revision != ZFCP_CT_REVISION)
+       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;
+
+
+       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
index 576628fd5ebe997c0d141060bfc7e739556d2d55..3a0702537305dafd787c0f2f9047125741f9a382 100644 (file)
@@ -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>
 #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_device)
        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_device)
        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 *ccw_device)
        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,10 +207,49 @@ zfcp_ccw_set_offline(struct ccw_device *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
  *
@@ -222,4 +285,3 @@ zfcp_ccw_unregister(void)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 159c01ed669400a7de376c8d62f54c57bb3354ac..f2f9ce13276e32402eb53964c961fcecf9440f59 100644 (file)
@@ -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> 
  * 
 #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 *****************************************/
 
 #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); \
-               }
+/* logging routine for zfcp */
+#define _ZFCP_LOG(fmt, args...) \
+       printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __FUNCTION__, \
+              __LINE__ , ##args);
 
-#define ZFCP_LOG(ll, m...) \
-               if (ZFCP_LOG_CHECK(ll)) \
-                       _ZFCP_LOG(m)
+#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
index ec3fe77c3af4e10b45f56709b976e707f30a3af8..20618f67f7cfc717c2d74499b2c01d0492780232 100644 (file)
@@ -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> 
  * 
  */
 
 #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 *unit, int clear_mask)
        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 zfcp_erp_action *erp_action)
                                                 "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 *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_unit *unit, int result)
        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_port *port, int result)
        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 zfcp_adapter *adapter, int result)
 {
        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 zfcp_erp_action *erp_action, int close)
 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(struct zfcp_erp_action *erp_action)
         * 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(struct zfcp_erp_action *erp_action)
                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_lookup(struct zfcp_erp_action *erp_action)
        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_action *erp_action)
        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_action *erp_action)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 685edbef5f7627eda2690aef7441d3b4d4da8e6e..dc39b5ed8a899a314a73b1062377f1bd4f5bdde9 100644 (file)
@@ -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(struct device *, u32);
 extern int  zfcp_sysfs_unit_create_files(struct device *);
 extern void zfcp_sysfs_unit_remove_files(struct device *);
 extern void zfcp_sysfs_port_release(struct device *);
-extern int  zfcp_sysfs_port_shutdown(struct zfcp_port *);
 extern void zfcp_sysfs_unit_release(struct device *);
 
 /**************************** CONFIGURATION  *********************************/
@@ -65,7 +65,6 @@ extern void   zfcp_unit_dequeue(struct zfcp_unit *);
 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(struct zfcp_qdio_queue *,
                                    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 zfcp_erp_action *);
 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_abort_fcp_command(
 
 /******************************** 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(struct fcp_rsp_iu *);
 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 zfcp_adapter *);
 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
index 968e265b57216e7b14357d797ed36909c9dc1e7b..12b7176b888f6d8c4a539ba06a27b706fe227e3f 100644 (file)
@@ -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_task_handler(struct zfcp_fsf_req *);
 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 *adapter, u32 fsf_cmd, int kmalloc_flags)
  *
  * 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_req *fsf_req)
        /* 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_req *fsf_req)
                              (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_req *fsf_req)
                               (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_req *fsf_req)
 
        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_req *fsf_req)
                             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 *adapter, int req_flags)
        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 *adapter, int req_flags)
                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 *adapter, int req_flags)
        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 *adapter, int req_flags)
        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 *fsf_req)
            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_fsf_req *fsf_req)
 
        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_fsf_req *fsf_req)
                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_fsf_req *fsf_req)
                              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 old_req_id,
                           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 old_req_id,
                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 old_req_id,
                              "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 old_req_id,
                       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(struct zfcp_fsf_req *new_fsf_req)
        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
+/**
+ * zfcp_fsf_send_ct_handler - handler for Generic Service requests
+ * @fsf_req: pointer to struct zfcp_fsf_req
  *
- * returns:    
+ * 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,180 +1613,514 @@ zfcp_fsf_send_generic_handler(struct zfcp_fsf_req *fsf_req)
        }
 
        /* 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_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(1, "FSF_REQUEST_BUF_NOT_VALID\n");
+       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;
-
-       /* 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;
+        int bytes;
+       int ret = 0;
+
+       port = els->port;
+       adapter = port->adapter;
+
+        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;
        }
 
-       erp_action->fsf_req->erp_action = erp_action;
-       /* no information from us to adapter, set nothing */
+       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 "
+       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);
@@ -1702,7 +2146,8 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
  * 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(struct zfcp_fsf_req *fsf_req) {
                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(struct zfcp_fsf_req *fsf_req) {
                        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(struct zfcp_fsf_req *fsf_req) {
                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(struct zfcp_fsf_req *fsf_req) {
 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_action *erp_action)
                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_fsf_req *fsf_req)
        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_fsf_req *fsf_req)
        }
 
        /* 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_fsf_req *fsf_req)
                 */
                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_fsf_req *fsf_req)
 
        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_fsf_req *fsf_req)
                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_fsf_req *fsf_req)
        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_fsf_req *fsf_req)
        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_fsf_req *fsf_req)
 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_action *erp_action)
                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_fsf_req *fsf_req)
                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_erp_action *erp_action)
        /* 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(struct zfcp_fsf_req *fsf_req)
        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(struct zfcp_fsf_req *fsf_req)
        }
 
        /* 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(struct zfcp_fsf_req *fsf_req)
                              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(struct zfcp_fsf_req *fsf_req)
                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(struct zfcp_fsf_req *fsf_req)
 
        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(struct zfcp_fsf_req *fsf_req)
                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(struct zfcp_fsf_req *fsf_req)
        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(struct zfcp_fsf_req *fsf_req)
 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_action *erp_action)
                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_action *erp_action)
        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_fsf_req *fsf_req)
 {
        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_fsf_req *fsf_req)
        }
 
        /* 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_fsf_req *fsf_req)
                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_fsf_req *fsf_req)
                        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_fsf_req *fsf_req)
                                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_fsf_req *fsf_req)
 
        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_fsf_req *fsf_req)
                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_fsf_req *fsf_req)
        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_fsf_req *fsf_req)
        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_fsf_req *fsf_req)
 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_action *erp_action)
                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_fsf_req *fsf_req)
 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 zfcp_adapter *adapter,
         *      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 zfcp_adapter *adapter,
                 */
                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 zfcp_adapter *adapter,
                 */
                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 zfcp_adapter *adapter,
                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_management(struct zfcp_adapter *adapter,
        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_management(struct zfcp_adapter *adapter,
        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 zfcp_fsf_req *fsf_req)
 {
        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 zfcp_fsf_req *fsf_req)
        }
 
        /* 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 zfcp_fsf_req *fsf_req)
                              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_fsf_req *fsf_req)
                              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_fsf_req *fsf_req)
                                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_fsf_req *fsf_req)
                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 zfcp_fsf_req *fsf_req)
                                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_fsf_req *fsf_req)
                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_fsf_req *fsf_req)
                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 zfcp_fsf_req *fsf_req)
                                 "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_fsf_req *fsf_req)
                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 zfcp_fsf_req *fsf_req)
                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_fsf_req *fsf_req)
                        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_fsf_req *fsf_req)
                        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 zfcp_fsf_req *fsf_req)
                        /* 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 zfcp_fsf_req *fsf_req)
        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_management_handler(struct zfcp_fsf_req *fsf_req)
        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
  *
@@ -3930,6 +4838,54 @@ zfcp_fsf_req_create_sbal_check(unsigned long *flags,
        return 0;
 }
 
+/*
+ * 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
  *
@@ -3947,149 +4903,65 @@ zfcp_fsf_req_create_sbal_check(unsigned long *flags,
  *             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 *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 *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 *fsf_req, struct timer_list *timer)
                       "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 *fsf_req, struct timer_list *timer)
                 * 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 *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
index 4f7c9365af35c0b5b504b3d036b45628ba254097..d5f70386119b7d946a802815c7b9fbd4f5b51e0e 100644 (file)
@@ -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> 
  * 
 #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
 #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
 
 #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
 #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
 
 /* 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 */
index 97e667fbf51f97477a218af95ecd9226633d2bbe..8ae02d969b384ee9287fa38288d9479636f2fdf8 100644 (file)
@@ -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
  * 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(struct zfcp_adapter *,
                                         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_device *ccw_device,
        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_device *ccw_device,
         */
 
        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_adapter *adapter, void *sbale_addr)
                       (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_adapter *adapter, void *sbale_addr)
        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 *buf[], int first, int clean_count)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 5a15a65694c458bff6dd71336ec797b74dfea4df..b72851365a870c53ca0f1a40b28883a5f3b8174e 100644 (file)
@@ -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>
 
 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_device *sdpnt)
        }
 }
 
-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_device *sdp)
        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)
+zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
 {
-       /* 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);
+       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 *adapter, int channel, int id, int lun)
  *             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 * scpnt)
  * 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 zfcp_unit *unit, u8 tm_flags)
  * 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 * scpnt)
  * 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_adapter *adapter)
 }
 
 
-/**
- * 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_sysfs_sdev_attrs[] = {
 };
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 8e09e042c3b3b87cbb7c1de12635cf04ecdd2408..6808930ef8197ff9722dda9f89aba3fe45e9b3c7 100644 (file)
@@ -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>
  * 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\n", atomic_read(&adapter->status));
 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 device *dev,
                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_attrs[] = {
        &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 device *dev)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 9908f256626885a7e93cd059cf746e14409d689c..988dceab5820c9f5cafaadc2a07ed2c8ce5c0b75 100644 (file)
@@ -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>
  * 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_##_name##_store(struct device_driver *drv, \
 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_attrs[] = {
        &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 device_driver *drv)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 2dc451b0b005b56ddcf92f52eac4a7fc07016194..0ead4498930f0bf7c5a181d5c68d0eb08e8df902 100644 (file)
@@ -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 device *dev, const char *buf, size_t count)
                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 device *dev, char *buf)
 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_common_attr_group = {
        .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 device *dev, u32 flags)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX
index 88af5b6353480e428afbf362ef725f3d0c8cdf16..2f65d9165c407e870ab995f956e5c1a4a53f4763 100644 (file)
@@ -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 device *dev, const char *buf, size_t count)
                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 device *dev)
 }
 
 #undef ZFCP_LOG_AREA
-#undef ZFCP_LOG_AREA_PREFIX