fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / s390 / scsi / zfcp_erp.c
index 57cb628..c88babc 100644 (file)
@@ -1,18 +1,8 @@
 /* 
- * 
- * linux/drivers/s390/scsi/zfcp_erp.c 
- * 
- * FCP adapter driver for IBM eServer zSeries 
- * 
- * (C) Copyright IBM Corp. 2002, 2004
- *
- * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
- *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
- *            Aron Zeh
- *            Wolfgang Taphorn
- *            Stefan Bader <stefan.bader@de.ibm.com> 
- *            Heiko Carstens <heiko.carstens@de.ibm.com> 
- *            Andreas Herrmann <aherrman@de.ibm.com>
+ * This file is part of the zfcp device driver for
+ * FCP adapters for IBM System z9 and zSeries.
+ *
+ * (C) Copyright IBM Corp. 2002, 2006
  * 
  * This program is free software; you can redistribute it and/or modify 
  * it under the terms of the GNU General Public License as published by 
@@ -74,8 +64,6 @@ static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int);
 static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *);
 static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int);
 static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *);
 static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *);
 static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *);
 static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *);
@@ -103,10 +91,10 @@ static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *);
 static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *);
 static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *);
 
-static int zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
-static int zfcp_erp_action_dismiss_port(struct zfcp_port *);
-static int zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
-static int zfcp_erp_action_dismiss(struct zfcp_erp_action *);
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *);
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
+static void zfcp_erp_action_dismiss(struct zfcp_erp_action *);
 
 static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *,
                                   struct zfcp_port *, struct zfcp_unit *);
@@ -122,8 +110,62 @@ static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
 static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
 
 static void zfcp_erp_memwait_handler(unsigned long);
-static void zfcp_erp_timeout_handler(unsigned long);
-static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *);
+
+/**
+ * zfcp_close_qdio - close qdio queues for an adapter
+ */
+static void zfcp_close_qdio(struct zfcp_adapter *adapter)
+{
+       struct zfcp_qdio_queue *req_queue;
+       int first, count;
+
+       if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+               return;
+
+       /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
+       req_queue = &adapter->request_queue;
+       write_lock_irq(&req_queue->queue_lock);
+       atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
+       write_unlock_irq(&req_queue->queue_lock);
+
+       debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
+       while (qdio_shutdown(adapter->ccw_device,
+                            QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
+               msleep(1000);
+       debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
+
+       /* cleanup used outbound sbals */
+       count = atomic_read(&req_queue->free_count);
+       if (count < QDIO_MAX_BUFFERS_PER_Q) {
+               first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q;
+               count = QDIO_MAX_BUFFERS_PER_Q - count;
+               zfcp_qdio_zero_sbals(req_queue->buffer, first, count);
+       }
+       req_queue->free_index = 0;
+       atomic_set(&req_queue->free_count, 0);
+       req_queue->distance_from_int = 0;
+       adapter->response_queue.free_index = 0;
+       atomic_set(&adapter->response_queue.free_count, 0);
+}
+
+/**
+ * zfcp_close_fsf - stop FSF operations for an adapter
+ *
+ * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of
+ * requests waiting for completion; especially this returns SCSI commands
+ * with error state).
+ */
+static void zfcp_close_fsf(struct zfcp_adapter *adapter)
+{
+       /* close queues to ensure that buffers are not accessed by adapter */
+       zfcp_close_qdio(adapter);
+       zfcp_fsf_req_dismiss_all(adapter);
+       /* reset FSF request sequence number */
+       adapter->fsf_req_seq_no = 0;
+       /* all ports and units are closed */
+       zfcp_erp_modify_adapter_status(adapter,
+                                      ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
+}
 
 /**
  * zfcp_fsf_request_timeout_handler - called if a request timed out
@@ -132,42 +174,20 @@ static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *);
  * This function needs to be called if requests (ELS, Generic Service,
  * or SCSI commands) exceed a certain time limit. The assumption is
  * that after the time limit the adapter get stuck. So we trigger a reopen of
- * the adapter. This should not be used for error recovery, SCSI abort
- * commands and SCSI requests from SCSI mid-layer.
+ * the adapter.
  */
-void
-zfcp_fsf_request_timeout_handler(unsigned long data)
+static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
-       struct zfcp_adapter *adapter;
-
-       adapter = (struct zfcp_adapter *) data;
-
+       struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
        zfcp_erp_adapter_reopen(adapter, 0);
 }
 
-/*
- * function:   zfcp_fsf_scsi_er_timeout_handler
- *
- * purpose:     This function needs to be called whenever a SCSI error recovery
- *              action (abort/reset) does not return.
- *              Re-opening the adapter means that the command can be returned
- *              by zfcp (it is guarranteed that it does not return via the
- *              adapter anymore). The buffer can then be used again.
- *    
- * returns:     sod all
- */
-void
-zfcp_fsf_scsi_er_timeout_handler(unsigned long data)
+void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
 {
-       struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-
-       ZFCP_LOG_NORMAL("warning: SCSI error recovery timed out. "
-                       "Restarting all operations on the adapter %s\n",
-                       zfcp_get_busid_by_adapter(adapter));
-       debug_text_event(adapter->erp_dbf, 1, "eh_lmem_tout");
-       zfcp_erp_adapter_reopen(adapter, 0);
-
-       return;
+       fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
+       fsf_req->timer.data = (unsigned long) fsf_req->adapter;
+       fsf_req->timer.expires = timeout;
+       add_timer(&fsf_req->timer);
 }
 
 /*
@@ -177,7 +197,7 @@ zfcp_fsf_scsi_er_timeout_handler(unsigned long data)
  *             initiates adapter recovery which is done
  *             asynchronously
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 int
@@ -213,7 +233,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
  * purpose:    Wrappper for zfcp_erp_adapter_reopen_internal
  *              used to ensure the correct locking
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 int
@@ -231,13 +251,6 @@ zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 int
 zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask)
 {
@@ -251,13 +264,6 @@ zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 int
 zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask)
 {
@@ -271,13 +277,6 @@ zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 int
 zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
 {
@@ -304,22 +303,18 @@ zfcp_erp_adisc(struct zfcp_port *port)
        struct zfcp_ls_adisc *adisc;
        void *address = NULL;
        int retval = 0;
-       struct timer_list *timer;
 
-       send_els = kmalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
+       send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
        if (send_els == NULL)
                goto nomem;
-       memset(send_els, 0, sizeof(*send_els));
 
-       send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+       send_els->req = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
        if (send_els->req == NULL)
                goto nomem;
-       memset(send_els->req, 0, sizeof(*send_els->req));
 
-       send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+       send_els->resp = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
        if (send_els->resp == NULL)
                goto nomem;
-       memset(send_els->resp, 0, sizeof(*send_els->resp));
 
        address = (void *) get_zeroed_page(GFP_ATOMIC);
        if (address == NULL)
@@ -354,22 +349,11 @@ zfcp_erp_adisc(struct zfcp_port *port)
                      (wwn_t) adisc->wwnn, adisc->hard_nport_id,
                      adisc->nport_id);
 
-       timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
-       if (!timer)
-               goto nomem;
-
-       init_timer(timer);
-       timer->function = zfcp_fsf_request_timeout_handler;
-       timer->data = (unsigned long) adapter;
-       timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
-       send_els->timer = timer;
-
        retval = zfcp_fsf_send_els(send_els);
        if (retval != 0) {
                ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
                                "0x%08x on adapter %s\n", send_els->d_id,
                                zfcp_get_busid_by_adapter(adapter));
-               del_timer(send_els->timer);
                goto freemem;
        }
 
@@ -381,7 +365,6 @@ zfcp_erp_adisc(struct zfcp_port *port)
        if (address != NULL)
                __free_pages(send_els->req->page, 0);
        if (send_els != NULL) {
-               kfree(send_els->timer);
                kfree(send_els->req);
                kfree(send_els->resp);
                kfree(send_els);
@@ -407,9 +390,6 @@ zfcp_erp_adisc_handler(unsigned long data)
        struct zfcp_ls_adisc_acc *adisc;
 
        send_els = (struct zfcp_send_els *) data;
-
-       del_timer(send_els->timer);
-
        adapter = send_els->adapter;
        port = send_els->port;
        d_id = send_els->d_id;
@@ -458,7 +438,6 @@ zfcp_erp_adisc_handler(unsigned long data)
  out:
        zfcp_port_put(port);
        __free_pages(send_els->req->page, 0);
-       kfree(send_els->timer);
        kfree(send_els->req);
        kfree(send_els->resp);
        kfree(send_els);
@@ -503,7 +482,7 @@ zfcp_test_link(struct zfcp_port *port)
  *             initiates Forced Reopen recovery which is done
  *             asynchronously
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 static int
@@ -543,7 +522,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask)
  * purpose:    Wrappper for zfcp_erp_port_forced_reopen_internal
  *              used to ensure the correct locking
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 int
@@ -570,7 +549,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask)
  *             initiates Reopen recovery which is done
  *             asynchronously
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 static int
@@ -639,7 +618,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask)
  *             initiates Reopen recovery which is done
  *             asynchronously
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 static int
@@ -704,17 +683,10 @@ zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    disable I/O,
- *             return any open requests and clean them up,
- *             aim: no pending and incoming I/O
- *
- * returns:
+/**
+ * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests
  */
-static void
-zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
+static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
 {
        debug_text_event(adapter->erp_dbf, 6, "a_bl");
        zfcp_erp_modify_adapter_status(adapter,
@@ -722,15 +694,10 @@ zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
                                       clear_mask, ZFCP_CLEAR);
 }
 
-/*
- * function:   
- *
- * purpose:    enable I/O
- *
- * returns:
+/**
+ * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests
  */
-static void
-zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
+static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
 {
        debug_text_event(adapter->erp_dbf, 6, "a_ubl");
        atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
@@ -812,13 +779,6 @@ zfcp_erp_unit_unblock(struct zfcp_unit *unit)
        atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static void
 zfcp_erp_action_ready(struct zfcp_erp_action *erp_action)
 {
@@ -889,18 +849,16 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
 
        if (erp_action->fsf_req) {
-               /* take lock to ensure that request is not being deleted meanwhile */
-               spin_lock(&adapter->fsf_req_list_lock);
-               /* check whether fsf req does still exist */
-               list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
-                   if (fsf_req == erp_action->fsf_req)
-                       break;
-               if (fsf_req && (fsf_req->erp_action == erp_action)) {
+               /* take lock to ensure that request is not deleted meanwhile */
+               spin_lock(&adapter->req_list_lock);
+               if ((!zfcp_reqlist_ismember(adapter,
+                                           erp_action->fsf_req->req_id)) &&
+                   (fsf_req->erp_action == erp_action)) {
                        /* fsf_req still exists */
                        debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
                        debug_event(adapter->erp_dbf, 3, &fsf_req,
                                    sizeof (unsigned long));
-                       /* dismiss fsf_req of timed out or dismissed erp_action */
+                       /* dismiss fsf_req of timed out/dismissed erp_action */
                        if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED |
                                                  ZFCP_STATUS_ERP_TIMEDOUT)) {
                                debug_text_event(adapter->erp_dbf, 3,
@@ -933,77 +891,50 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
                         */
                        erp_action->fsf_req = NULL;
                }
-               spin_unlock(&adapter->fsf_req_list_lock);
+               spin_unlock(&adapter->req_list_lock);
        } else
                debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq");
 
        return retval;
 }
 
-/*
- * purpose:    generic handler for asynchronous events related to erp_action events
- *             (normal completion, time-out, dismissing, retry after
- *             low memory condition)
- *
- * note:       deletion of timer is not required (e.g. in case of a time-out),
- *             but a second try does no harm,
- *             we leave it in here to allow for greater simplification
+/**
+ * zfcp_erp_async_handler_nolock - complete erp_action
  *
- * returns:    0 - there was an action to handle
- *             !0 - otherwise
+ * Used for normal completion, time-out, dismissal and failure after
+ * low memory condition.
  */
-static int
-zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
-                             unsigned long set_mask)
+static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
+                                         unsigned long set_mask)
 {
-       int retval;
        struct zfcp_adapter *adapter = erp_action->adapter;
 
        if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
                debug_text_event(adapter->erp_dbf, 2, "a_asyh_ex");
                debug_event(adapter->erp_dbf, 2, &erp_action->action,
                            sizeof (int));
-               if (!(set_mask & ZFCP_STATUS_ERP_TIMEDOUT))
-                       del_timer(&erp_action->timer);
                erp_action->status |= set_mask;
                zfcp_erp_action_ready(erp_action);
-               retval = 0;
        } else {
                /* action is ready or gone - nothing to do */
                debug_text_event(adapter->erp_dbf, 3, "a_asyh_gone");
                debug_event(adapter->erp_dbf, 3, &erp_action->action,
                            sizeof (int));
-               retval = 1;
        }
-
-       return retval;
 }
 
-/*
- * purpose:    generic handler for asynchronous events related to erp_action
- *               events        (normal completion, time-out, dismissing, retry after
- *             low memory condition)
- *
- * note:       deletion of timer is not required (e.g. in case of a time-out),
- *             but a second try does no harm,
- *             we leave it in here to allow for greater simplification
- *
- * returns:    0 - there was an action to handle
- *             !0 - otherwise
+/**
+ * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking
  */
-int
-zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
-                      unsigned long set_mask)
+void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
+                           unsigned long set_mask)
 {
        struct zfcp_adapter *adapter = erp_action->adapter;
        unsigned long flags;
-       int retval;
 
        write_lock_irqsave(&adapter->erp_lock, flags);
-       retval = zfcp_erp_async_handler_nolock(erp_action, set_mask);
+       zfcp_erp_async_handler_nolock(erp_action, set_mask);
        write_unlock_irqrestore(&adapter->erp_lock, flags);
-
-       return retval;
 }
 
 /*
@@ -1028,8 +959,7 @@ zfcp_erp_memwait_handler(unsigned long data)
  *             action gets an appropriate flag and will be processed
  *             accordingly
  */
-static void
-zfcp_erp_timeout_handler(unsigned long data)
+void zfcp_erp_timeout_handler(unsigned long data)
 {
        struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
        struct zfcp_adapter *adapter = erp_action->adapter;
@@ -1040,17 +970,15 @@ zfcp_erp_timeout_handler(unsigned long data)
        zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT);
 }
 
-/*
- * purpose:    is called for an erp_action which needs to be ended
- *             though not being done,
- *             this is usually required if an higher is generated,
- *             action gets an appropriate flag and will be processed
- *             accordingly
+/**
+ * zfcp_erp_action_dismiss - dismiss an erp_action
  *
- * locks:      erp_lock held (thus we need to call another handler variant)
+ * adapter->erp_lock must be held
+ * 
+ * Dismissal of an erp_action is usually required if an erp_action of
+ * higher priority is generated.
  */
-static int
-zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
 {
        struct zfcp_adapter *adapter = erp_action->adapter;
 
@@ -1058,8 +986,6 @@ zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
        debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int));
 
        zfcp_erp_async_handler_nolock(erp_action, ZFCP_STATUS_ERP_DISMISSED);
-
-       return 0;
 }
 
 int
@@ -1356,13 +1282,6 @@ zfcp_erp_strategy_check_action(struct zfcp_erp_action *erp_action, int retval)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
 {
@@ -1538,13 +1457,6 @@ zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, int result)
        return result;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_strategy_statechange(int action,
                              u32 status,
@@ -1586,13 +1498,6 @@ zfcp_erp_strategy_statechange(int action,
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static inline int
 zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
 {
@@ -1605,13 +1510,6 @@ zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
             !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status));
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
 {
@@ -1642,13 +1540,6 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
        return result;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
 {
@@ -1678,13 +1569,6 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
        return result;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
 {
@@ -1764,13 +1648,6 @@ zfcp_erp_strategy_followup_actions(int action,
        return 0;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter)
 {
@@ -1809,12 +1686,6 @@ zfcp_erp_wait(struct zfcp_adapter *adapter)
        return retval;
 }
 
-/*
- * function:   zfcp_erp_modify_adapter_status
- *
- * purpose:    
- *
- */
 void
 zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter,
                               u32 mask, int set_or_clear)
@@ -1901,7 +1772,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear)
  * purpose:    Wrappper for zfcp_erp_port_reopen_all_internal
  *              used to ensure the correct locking
  *
- * returns:    0       - initiated action succesfully
+ * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
 int
@@ -1919,13 +1790,6 @@ zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, int clear_mask)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:    FIXME
- */
 static int
 zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
 {
@@ -2071,8 +1935,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
                          &erp_action->adapter->status);
 
  failed_openfcp:
-       zfcp_erp_adapter_strategy_close_qdio(erp_action);
-       zfcp_erp_adapter_strategy_close_fsf(erp_action);
+       zfcp_close_fsf(erp_action->adapter);
  failed_qdio:
  out:
        return retval;
@@ -2124,7 +1987,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
                sbale = &(adapter->response_queue.buffer[i]->element[0]);
                sbale->length = 0;
                sbale->flags = SBAL_FLAGS_LAST_ENTRY;
-               sbale->addr = 0;
+               sbale->addr = NULL;
        }
 
        ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, "
@@ -2177,69 +2040,6 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:    zfcp_qdio_cleanup
- *
- * purpose:    cleans up QDIO operation for the specified adapter
- *
- * returns:    0 - successful cleanup
- *             !0 - failed cleanup
- */
-int
-zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
-{
-       int retval = ZFCP_ERP_SUCCEEDED;
-       int first_used;
-       int used_count;
-       struct zfcp_adapter *adapter = erp_action->adapter;
-
-       if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
-               ZFCP_LOG_DEBUG("error: attempt to shut down inactive QDIO "
-                              "queues on adapter %s\n",
-                              zfcp_get_busid_by_adapter(adapter));
-               retval = ZFCP_ERP_FAILED;
-               goto out;
-       }
-
-       /*
-        * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that
-        * do_QDIO won't be called while qdio_shutdown is in progress.
-        */
-
-       write_lock_irq(&adapter->request_queue.queue_lock);
-       atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
-       write_unlock_irq(&adapter->request_queue.queue_lock);
-
-       debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
-       while (qdio_shutdown(adapter->ccw_device,
-                            QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
-               msleep(1000);
-       debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
-
-       /*
-        * First we had to stop QDIO operation.
-        * Now it is safe to take the following actions.
-        */
-
-       /* Cleanup only necessary when there are unacknowledged buffers */
-       if (atomic_read(&adapter->request_queue.free_count)
-           < QDIO_MAX_BUFFERS_PER_Q) {
-               first_used = (adapter->request_queue.free_index +
-                             atomic_read(&adapter->request_queue.free_count))
-                       % QDIO_MAX_BUFFERS_PER_Q;
-               used_count = QDIO_MAX_BUFFERS_PER_Q -
-                       atomic_read(&adapter->request_queue.free_count);
-               zfcp_qdio_zero_sbals(adapter->request_queue.buffer,
-                                    first_used, used_count);
-       }
-       adapter->response_queue.free_index = 0;
-       atomic_set(&adapter->response_queue.free_count, 0);
-       adapter->request_queue.free_index = 0;
-       atomic_set(&adapter->request_queue.free_count, 0);
-       adapter->request_queue.distance_from_int = 0;
- out:
-       return retval;
-}
 
 static int
 zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action)
@@ -2271,10 +2071,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
                atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
                                  &adapter->status);
                ZFCP_LOG_DEBUG("Doing exchange config data\n");
-               write_lock(&adapter->erp_lock);
+               write_lock_irq(&adapter->erp_lock);
                zfcp_erp_action_to_running(erp_action);
-               write_unlock(&adapter->erp_lock);
-               zfcp_erp_timeout_init(erp_action);
+               write_unlock_irq(&adapter->erp_lock);
                if (zfcp_fsf_exchange_config_data(erp_action)) {
                        retval = ZFCP_ERP_FAILED;
                        debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf");
@@ -2339,11 +2138,10 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
        adapter = erp_action->adapter;
        atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
 
-       write_lock(&adapter->erp_lock);
+       write_lock_irq(&adapter->erp_lock);
        zfcp_erp_action_to_running(erp_action);
-       write_unlock(&adapter->erp_lock);
+       write_unlock_irq(&adapter->erp_lock);
 
-       zfcp_erp_timeout_init(erp_action);
        ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
        if (ret == -EOPNOTSUPP) {
                debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
@@ -2361,22 +2159,15 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
                              "%s)\n", zfcp_get_busid_by_adapter(adapter));
                ret = ZFCP_ERP_FAILED;
        }
-       if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) {
-               ZFCP_LOG_INFO("error: exchange port data failed (adapter "
+
+       /* don't treat as error for the sake of compatibility */
+       if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status))
+               ZFCP_LOG_INFO("warning: exchange port data failed (adapter "
                              "%s\n", zfcp_get_busid_by_adapter(adapter));
-               ret = ZFCP_ERP_FAILED;
-       }
 
        return ret;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
                                              *erp_action)
@@ -2402,35 +2193,6 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
        return retval;
 }
 
-/*
- * function:    zfcp_fsf_cleanup
- *
- * purpose:    cleanup FSF operation for specified adapter
- *
- * returns:    0 - FSF operation successfully cleaned up
- *             !0 - failed to cleanup FSF operation for this adapter
- */
-static int
-zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action)
-{
-       int retval = ZFCP_ERP_SUCCEEDED;
-       struct zfcp_adapter *adapter = erp_action->adapter;
-
-       /*
-        * wake waiting initiators of requests,
-        * return SCSI commands (with error status),
-        * clean up all requests (synchronously)
-        */
-       zfcp_fsf_req_dismiss_all(adapter);
-       /* reset FSF request sequence number */
-       adapter->fsf_req_seq_no = 0;
-       /* all ports and units are closed */
-       zfcp_erp_modify_adapter_status(adapter,
-                                      ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
-
-       return retval;
-}
-
 /*
  * function:   
  *
@@ -2545,13 +2307,6 @@ zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action)
 {
@@ -2566,15 +2321,6 @@ zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- *
- * FIXME(design):      currently only prepared for fabric (nameserver!)
- */
 static int
 zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
 {
@@ -2690,13 +2436,6 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
 {
@@ -2790,7 +2529,6 @@ zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_port *port = erp_action->port;
 
-       zfcp_erp_timeout_init(erp_action);
        retval = zfcp_fsf_close_physical_port(erp_action);
        if (retval == -ENOMEM) {
                debug_text_event(adapter->erp_dbf, 5, "o_pfstc_nomem");
@@ -2813,13 +2551,6 @@ zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
 {
@@ -2854,7 +2585,6 @@ zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_port *port = erp_action->port;
 
-       zfcp_erp_timeout_init(erp_action);
        retval = zfcp_fsf_close_port(erp_action);
        if (retval == -ENOMEM) {
                debug_text_event(adapter->erp_dbf, 5, "p_pstc_nomem");
@@ -2892,7 +2622,6 @@ zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_port *port = erp_action->port;
 
-       zfcp_erp_timeout_init(erp_action);
        retval = zfcp_fsf_open_port(erp_action);
        if (retval == -ENOMEM) {
                debug_text_event(adapter->erp_dbf, 5, "p_psto_nomem");
@@ -2930,7 +2659,6 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_port *port = erp_action->port;
 
-       zfcp_erp_timeout_init(erp_action);
        retval = zfcp_ns_gid_pn_request(erp_action);
        if (retval == -ENOMEM) {
                debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
@@ -3022,13 +2750,6 @@ zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
 static int
 zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
 {
@@ -3063,7 +2784,6 @@ zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_unit *unit = erp_action->unit;
 
-       zfcp_erp_timeout_init(erp_action);
        retval = zfcp_fsf_close_unit(erp_action);
        if (retval == -ENOMEM) {
                debug_text_event(adapter->erp_dbf, 5, "u_ustc_nomem");
@@ -3104,7 +2824,6 @@ zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_unit *unit = erp_action->unit;
 
-       zfcp_erp_timeout_init(erp_action);
        retval = zfcp_fsf_open_unit(erp_action);
        if (retval == -ENOMEM) {
                debug_text_event(adapter->erp_dbf, 5, "u_usto_nomem");
@@ -3129,21 +2848,13 @@ zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
-static inline void
-zfcp_erp_timeout_init(struct zfcp_erp_action *erp_action)
+void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
 {
-       init_timer(&erp_action->timer);
-       erp_action->timer.function = zfcp_erp_timeout_handler;
-       erp_action->timer.data = (unsigned long) erp_action;
-       /* jiffies will be added in zfcp_fsf_req_send */
-       erp_action->timer.expires = ZFCP_ERP_FSFREQ_TIMEOUT;
+       BUG_ON(!fsf_req->erp_action);
+       fsf_req->timer.function = zfcp_erp_timeout_handler;
+       fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
+       fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT;
+       add_timer(&fsf_req->timer);
 }
 
 /*
@@ -3331,13 +3042,6 @@ zfcp_erp_action_enqueue(int action,
        return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:
- */
 static int
 zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
 {
@@ -3402,9 +3106,13 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                break;
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
        case ZFCP_ERP_ACTION_REOPEN_PORT:
+               if (atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN,
+                                    &port->status)) {
+                       zfcp_port_put(port);
+                       break;
+               }
+
                if ((result == ZFCP_ERP_SUCCEEDED)
-                   && !atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN,
-                                        &port->status)
                    && !port->rport) {
                        struct fc_rport_identifiers ids;
                        ids.node_name = port->wwnn;
@@ -3418,12 +3126,30 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                                                "(adapter %s, wwpn=0x%016Lx)\n",
                                                zfcp_get_busid_by_port(port),
                                                port->wwpn);
-                       else
+                       else {
                                scsi_flush_work(adapter->scsi_host);
+                               port->rport->maxframe_size = port->maxframe_size;
+                               port->rport->supported_classes =
+                                       port->supported_classes;
+                       }
+               }
+               if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
+                       fc_remote_port_delete(port->rport);
+                       port->rport = NULL;
                }
                zfcp_port_put(port);
                break;
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+               if (result != ZFCP_ERP_SUCCEEDED) {
+                       struct zfcp_port *port;
+                       list_for_each_entry(port, &adapter->port_list_head, list)
+                               if (port->rport &&
+                                   !atomic_test_mask(ZFCP_STATUS_PORT_WKA,
+                                                     &port->status)) {
+                                       fc_remote_port_delete(port->rport);
+                                       port->rport = NULL;
+                               }
+               }
                zfcp_adapter_put(adapter);
                break;
        default:
@@ -3432,17 +3158,8 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
 }
 
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:    FIXME
- */
-static int
-zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
 {
-       int retval = 0;
        struct zfcp_port *port;
 
        debug_text_event(adapter->erp_dbf, 5, "a_actab");
@@ -3451,21 +3168,10 @@ zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
        else
                list_for_each_entry(port, &adapter->port_list_head, list)
                    zfcp_erp_action_dismiss_port(port);
-
-       return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:    FIXME
- */
-static int
-zfcp_erp_action_dismiss_port(struct zfcp_port *port)
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
 {
-       int retval = 0;
        struct zfcp_unit *unit;
        struct zfcp_adapter *adapter = port->adapter;
 
@@ -3476,38 +3182,18 @@ zfcp_erp_action_dismiss_port(struct zfcp_port *port)
        else
                list_for_each_entry(unit, &port->unit_list_head, list)
                    zfcp_erp_action_dismiss_unit(unit);
-
-       return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    
- *
- * returns:    FIXME
- */
-static int
-zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
 {
-       int retval = 0;
        struct zfcp_adapter *adapter = unit->port->adapter;
 
        debug_text_event(adapter->erp_dbf, 5, "u_actab");
        debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t));
        if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status))
                zfcp_erp_action_dismiss(&unit->erp_action);
-
-       return retval;
 }
 
-/*
- * function:   
- *
- * purpose:    moves erp_action to 'erp running list'
- *
- * returns:
- */
 static inline void
 zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
 {
@@ -3518,13 +3204,6 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
        list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
 }
 
-/*
- * function:   
- *
- * purpose:    moves erp_action to 'erp ready list'
- *
- * returns:
- */
 static inline void
 zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
 {
@@ -3535,11 +3214,6 @@ zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
        list_move(&erp_action->list, &erp_action->adapter->erp_ready_head);
 }
 
-/*
- * function:   zfcp_erp_port_boxed
- *
- * purpose:
- */
 void
 zfcp_erp_port_boxed(struct zfcp_port *port)
 {
@@ -3556,11 +3230,6 @@ zfcp_erp_port_boxed(struct zfcp_port *port)
        zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
 }
 
-/*
- * function:   zfcp_erp_unit_boxed
- *
- * purpose:
- */
 void
 zfcp_erp_unit_boxed(struct zfcp_unit *unit)
 {
@@ -3574,11 +3243,6 @@ zfcp_erp_unit_boxed(struct zfcp_unit *unit)
        zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
 }
 
-/*
- * function:   zfcp_erp_port_access_denied
- *
- * purpose:
- */
 void
 zfcp_erp_port_access_denied(struct zfcp_port *port)
 {
@@ -3595,11 +3259,6 @@ zfcp_erp_port_access_denied(struct zfcp_port *port)
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
-/*
- * function:   zfcp_erp_unit_access_denied
- *
- * purpose:
- */
 void
 zfcp_erp_unit_access_denied(struct zfcp_unit *unit)
 {
@@ -3613,11 +3272,6 @@ zfcp_erp_unit_access_denied(struct zfcp_unit *unit)
                        ZFCP_SET);
 }
 
-/*
- * function:   zfcp_erp_adapter_access_changed
- *
- * purpose:
- */
 void
 zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
 {
@@ -3628,7 +3282,7 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
                return;
 
        debug_text_event(adapter->erp_dbf, 3, "a_access_recover");
-       debug_event(adapter->erp_dbf, 3, &adapter->name, 8);
+       debug_event(adapter->erp_dbf, 3, zfcp_get_busid_by_adapter(adapter), 8);
 
        read_lock_irqsave(&zfcp_data.config_lock, flags);
        if (adapter->nameserver_port)
@@ -3639,11 +3293,6 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
-/*
- * function:   zfcp_erp_port_access_changed
- *
- * purpose:
- */
 void
 zfcp_erp_port_access_changed(struct zfcp_port *port)
 {
@@ -3672,11 +3321,6 @@ zfcp_erp_port_access_changed(struct zfcp_port *port)
                                zfcp_get_busid_by_adapter(adapter), port->wwpn);
 }
 
-/*
- * function:   zfcp_erp_unit_access_changed
- *
- * purpose:
- */
 void
 zfcp_erp_unit_access_changed(struct zfcp_unit *unit)
 {