Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[safe/jmp/linux-2.6] / drivers / s390 / scsi / zfcp_erp.c
index 4e16052..e3dbeda 100644 (file)
@@ -3,13 +3,15 @@
  *
  * Error Recovery Procedures (ERP).
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #define KMSG_COMPONENT "zfcp"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/kthread.h>
 #include "zfcp_ext.h"
+#include "zfcp_reqlist.h"
 
 #define ZFCP_MAX_ERPS                   3
 
@@ -26,7 +28,6 @@ enum zfcp_erp_steps {
        ZFCP_ERP_STEP_FSF_XCONFIG       = 0x0001,
        ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
        ZFCP_ERP_STEP_PORT_CLOSING      = 0x0100,
-       ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400,
        ZFCP_ERP_STEP_PORT_OPENING      = 0x0800,
        ZFCP_ERP_STEP_UNIT_CLOSING      = 0x1000,
        ZFCP_ERP_STEP_UNIT_OPENING      = 0x2000,
@@ -75,9 +76,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
        struct zfcp_adapter *adapter = act->adapter;
 
        list_move(&act->list, &act->adapter->erp_ready_head);
-       zfcp_rec_dbf_event_action("erardy1", act);
-       up(&adapter->erp_ready_sem);
-       zfcp_rec_dbf_event_thread("erardy2", adapter);
+       zfcp_dbf_rec_action("erardy1", act);
+       wake_up(&adapter->erp_ready_wq);
+       zfcp_dbf_rec_thread("erardy2", adapter->dbf);
 }
 
 static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
@@ -99,9 +100,12 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
 
        if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
                zfcp_erp_action_dismiss(&port->erp_action);
-       else
-               list_for_each_entry(unit, &port->unit_list_head, list)
-                   zfcp_erp_action_dismiss_unit(unit);
+       else {
+               read_lock(&port->unit_list_lock);
+               list_for_each_entry(unit, &port->unit_list, list)
+                       zfcp_erp_action_dismiss_unit(unit);
+               read_unlock(&port->unit_list_lock);
+       }
 }
 
 static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
@@ -110,9 +114,12 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
 
        if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
                zfcp_erp_action_dismiss(&adapter->erp_action);
-       else
-               list_for_each_entry(port, &adapter->port_list_head, list)
+       else {
+               read_lock(&adapter->port_list_lock);
+               list_for_each_entry(port, &adapter->port_list, list)
                    zfcp_erp_action_dismiss_port(port);
+               read_unlock(&adapter->port_list_lock);
+       }
 }
 
 static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
@@ -150,6 +157,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
                a_status = atomic_read(&adapter->status);
                if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
                        return 0;
+               if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
+                   !(a_status & ZFCP_STATUS_COMMON_OPEN))
+                       return 0; /* shutdown requested for closed adapter */
        }
 
        return need;
@@ -165,7 +175,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
 
        switch (need) {
        case ZFCP_ERP_ACTION_REOPEN_UNIT:
-               zfcp_unit_get(unit);
+               if (!get_device(&unit->dev))
+                       return NULL;
                atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
                erp_action = &unit->erp_action;
                if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
@@ -174,7 +185,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
 
        case ZFCP_ERP_ACTION_REOPEN_PORT:
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
-               zfcp_port_get(port);
+               if (!get_device(&port->dev))
+                       return NULL;
                zfcp_erp_action_dismiss_port(port);
                atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
                erp_action = &port->erp_action;
@@ -183,7 +195,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
                break;
 
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
-               zfcp_adapter_get(adapter);
+               kref_get(&adapter->ref);
                zfcp_erp_action_dismiss_adapter(adapter);
                atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
                erp_action = &adapter->erp_action;
@@ -213,8 +225,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
        int retval = 1, need;
        struct zfcp_erp_action *act = NULL;
 
-       if (!(atomic_read(&adapter->status) &
-             ZFCP_STATUS_ADAPTER_ERP_THREAD_UP))
+       if (!adapter->erp_thread)
                return -EIO;
 
        need = zfcp_erp_required_act(want, adapter, port, unit);
@@ -227,12 +238,11 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
                goto out;
        ++adapter->erp_total_count;
        list_add_tail(&act->list, &adapter->erp_ready_head);
-       up(&adapter->erp_ready_sem);
-       zfcp_rec_dbf_event_thread("eracte1", adapter);
+       wake_up(&adapter->erp_ready_wq);
+       zfcp_dbf_rec_thread("eracte1", adapter->dbf);
        retval = 0;
  out:
-       zfcp_rec_dbf_event_trigger(id, ref, want, need, act,
-                                  adapter, port, unit);
+       zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit);
        return retval;
 }
 
@@ -263,11 +273,16 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
 {
        unsigned long flags;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       write_lock(&adapter->erp_lock);
-       _zfcp_erp_adapter_reopen(adapter, clear, id, ref);
-       write_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       zfcp_erp_adapter_block(adapter, clear);
+       zfcp_scsi_schedule_rports_block(adapter);
+
+       write_lock_irqsave(&adapter->erp_lock, flags);
+       if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+               zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
+       else
+               zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
+                                       NULL, NULL, id, ref);
+       write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 /**
@@ -344,11 +359,9 @@ void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
        unsigned long flags;
        struct zfcp_adapter *adapter = port->adapter;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       write_lock(&adapter->erp_lock);
+       write_lock_irqsave(&adapter->erp_lock, flags);
        _zfcp_erp_port_forced_reopen(port, clear, id, ref);
-       write_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
@@ -376,15 +389,13 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
  */
 int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
 {
-       unsigned long flags;
        int retval;
+       unsigned long flags;
        struct zfcp_adapter *adapter = port->adapter;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       write_lock(&adapter->erp_lock);
+       write_lock_irqsave(&adapter->erp_lock, flags);
        retval = _zfcp_erp_port_reopen(port, clear, id, ref);
-       write_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       write_unlock_irqrestore(&adapter->erp_lock, flags);
 
        return retval;
 }
@@ -423,11 +434,9 @@ void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
        struct zfcp_port *port = unit->port;
        struct zfcp_adapter *adapter = port->adapter;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       write_lock(&adapter->erp_lock);
+       write_lock_irqsave(&adapter->erp_lock, flags);
        _zfcp_erp_unit_reopen(unit, clear, id, ref);
-       write_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 static int status_change_set(unsigned long mask, atomic_t *status)
@@ -443,54 +452,54 @@ static int status_change_clear(unsigned long mask, atomic_t *status)
 static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
 {
        if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
-               zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter);
+               zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
        atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
 }
 
 static void zfcp_erp_port_unblock(struct zfcp_port *port)
 {
        if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
-               zfcp_rec_dbf_event_port("erpubl1", NULL, port);
+               zfcp_dbf_rec_port("erpubl1", NULL, port);
        atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
 }
 
 static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
 {
        if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
-               zfcp_rec_dbf_event_unit("eruubl1", NULL, unit);
+               zfcp_dbf_rec_unit("eruubl1", NULL, unit);
        atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
 }
 
 static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
 {
        list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
-       zfcp_rec_dbf_event_action("erator1", erp_action);
+       zfcp_dbf_rec_action("erator1", erp_action);
 }
 
 static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
 {
        struct zfcp_adapter *adapter = act->adapter;
+       struct zfcp_fsf_req *req;
 
-       if (!act->fsf_req)
+       if (!act->fsf_req_id)
                return;
 
-       spin_lock(&adapter->req_list_lock);
-       if (zfcp_reqlist_find_safe(adapter, act->fsf_req) &&
-           act->fsf_req->erp_action == act) {
+       spin_lock(&adapter->req_list->lock);
+       req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
+       if (req && req->erp_action == act) {
                if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
                                   ZFCP_STATUS_ERP_TIMEDOUT)) {
-                       act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
-                       zfcp_rec_dbf_event_action("erscf_1", act);
-                       act->fsf_req->erp_action = NULL;
+                       req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
+                       zfcp_dbf_rec_action("erscf_1", act);
+                       req->erp_action = NULL;
                }
                if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
-                       zfcp_rec_dbf_event_action("erscf_2", act);
-               if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
-                                           ZFCP_STATUS_FSFREQ_DISMISSED))
-                       act->fsf_req = NULL;
+                       zfcp_dbf_rec_action("erscf_2", act);
+               if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
+                       act->fsf_req_id = 0;
        } else
-               act->fsf_req = NULL;
-       spin_unlock(&adapter->req_list_lock);
+               act->fsf_req_id = 0;
+       spin_unlock(&adapter->req_list->lock);
 }
 
 /**
@@ -540,8 +549,10 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
 {
        struct zfcp_port *port;
 
-       list_for_each_entry(port, &adapter->port_list_head, list)
+       read_lock(&adapter->port_list_lock);
+       list_for_each_entry(port, &adapter->port_list, list)
                _zfcp_erp_port_reopen(port, clear, id, ref);
+       read_unlock(&adapter->port_list_lock);
 }
 
 static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
@@ -549,44 +560,41 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
 {
        struct zfcp_unit *unit;
 
-       list_for_each_entry(unit, &port->unit_list_head, list)
+       read_lock(&port->unit_list_lock);
+       list_for_each_entry(unit, &port->unit_list, list)
                _zfcp_erp_unit_reopen(unit, clear, id, ref);
+       read_unlock(&port->unit_list_lock);
 }
 
-static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act)
+static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
 {
-       struct zfcp_adapter *adapter = act->adapter;
-       struct zfcp_port *port = act->port;
-       struct zfcp_unit *unit = act->unit;
-       u32 status = act->status;
-
-       /* initiate follow-up actions depending on success of finished action */
        switch (act->action) {
-
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
-               if (status == ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL);
-               else
-                       _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL);
+               _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
                break;
-
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
-               if (status == ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL);
-               else
-                       _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL);
+               _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
                break;
-
        case ZFCP_ERP_ACTION_REOPEN_PORT:
-               if (status == ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL);
-               else
-                       _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL);
+               _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
                break;
-
        case ZFCP_ERP_ACTION_REOPEN_UNIT:
-               if (status != ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
+               _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
+               break;
+       }
+}
+
+static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
+{
+       switch (act->action) {
+       case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+               _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
+               break;
+       case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+               _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
+               break;
+       case ZFCP_ERP_ACTION_REOPEN_PORT:
+               _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
                break;
        }
 }
@@ -595,23 +603,23 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
 {
        unsigned long flags;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       read_lock(&adapter->erp_lock);
+       read_lock_irqsave(&adapter->erp_lock, flags);
        if (list_empty(&adapter->erp_ready_head) &&
            list_empty(&adapter->erp_running_head)) {
                        atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
                                          &adapter->status);
                        wake_up(&adapter->erp_done_wqh);
        }
-       read_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       read_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
 {
-       if (zfcp_qdio_open(act->adapter))
+       struct zfcp_qdio *qdio = act->adapter->qdio;
+
+       if (zfcp_qdio_open(qdio))
                return ZFCP_ERP_FAILED;
-       init_waitqueue_head(&act->adapter->request_wq);
+       init_waitqueue_head(&qdio->req_q_wq);
        atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
        return ZFCP_ERP_SUCCEEDED;
 }
@@ -646,9 +654,10 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
                        return ZFCP_ERP_FAILED;
                }
 
-               zfcp_rec_dbf_event_thread_lock("erasfx1", adapter);
-               down(&adapter->erp_ready_sem);
-               zfcp_rec_dbf_event_thread_lock("erasfx2", adapter);
+               zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
+               wait_event(adapter->erp_ready_wq,
+                          !list_empty(&adapter->erp_ready_head));
+               zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
                if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
                        break;
 
@@ -687,9 +696,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
        if (ret)
                return ZFCP_ERP_FAILED;
 
-       zfcp_rec_dbf_event_thread_lock("erasox1", adapter);
-       down(&adapter->erp_ready_sem);
-       zfcp_rec_dbf_event_thread_lock("erasox2", adapter);
+       zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
+       wait_event(adapter->erp_ready_wq,
+                  !list_empty(&adapter->erp_ready_head));
+       zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
        if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
                return ZFCP_ERP_FAILED;
 
@@ -704,7 +714,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
        if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
                return ZFCP_ERP_FAILED;
 
-       atomic_set(&act->adapter->stat_miss, 16);
+       atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
        if (zfcp_status_read_refill(act->adapter))
                return ZFCP_ERP_FAILED;
 
@@ -716,9 +726,10 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
        struct zfcp_adapter *adapter = act->adapter;
 
        /* close queues to ensure that buffers are not accessed by adapter */
-       zfcp_qdio_close(adapter);
+       zfcp_qdio_close(adapter->qdio);
        zfcp_fsf_req_dismiss_all(adapter);
        adapter->fsf_req_seq_no = 0;
+       zfcp_fc_wka_ports_force_offline(adapter->gs);
        /* all ports and units are closed */
        zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
                                       ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
@@ -800,7 +811,7 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
                        return ZFCP_ERP_FAILED;
 
        case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
-               if (status & ZFCP_STATUS_PORT_PHYS_OPEN)
+               if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
                        return ZFCP_ERP_SUCCEEDED;
        }
        return ZFCP_ERP_FAILED;
@@ -845,21 +856,6 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
        return zfcp_erp_port_strategy_open_port(act);
 }
 
-void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
-{
-       int retval;
-       struct zfcp_port *port = container_of(work, struct zfcp_port,
-                                             gid_pn_work);
-
-       retval = zfcp_fc_ns_gid_pn(&port->erp_action);
-       if (retval == -ENOMEM)
-               zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
-       port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
-       if (retval)
-               zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
-       zfcp_port_put(port);
-}
-
 static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
 {
        struct zfcp_adapter *adapter = act->adapter;
@@ -873,28 +869,26 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
                if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
                        return zfcp_erp_open_ptp_port(act);
                if (!port->d_id) {
-                       zfcp_port_get(port);
-                       if (!queue_work(zfcp_data.work_queue,
-                                       &port->gid_pn_work))
-                               zfcp_port_put(port);
-                       return ZFCP_ERP_CONTINUES;
+                       zfcp_fc_trigger_did_lookup(port);
+                       return ZFCP_ERP_EXIT;
                }
-       case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
-               if (!port->d_id)
-                       return ZFCP_ERP_FAILED;
                return zfcp_erp_port_strategy_open_port(act);
 
        case ZFCP_ERP_STEP_PORT_OPENING:
                /* D_ID might have changed during open */
                if (p_status & ZFCP_STATUS_COMMON_OPEN) {
-                       if (port->d_id)
-                               return ZFCP_ERP_SUCCEEDED;
-                       else {
-                               act->step = ZFCP_ERP_STEP_PORT_CLOSING;
-                               return ZFCP_ERP_CONTINUES;
+                       if (!port->d_id) {
+                               zfcp_fc_trigger_did_lookup(port);
+                               return ZFCP_ERP_EXIT;
                        }
-               /* fall through otherwise */
+                       return ZFCP_ERP_SUCCEEDED;
                }
+               if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
+                       port->d_id = 0;
+                       _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
+                       return ZFCP_ERP_EXIT;
+               }
+               /* fall through otherwise */
        }
        return ZFCP_ERP_FAILED;
 }
@@ -902,19 +896,21 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
 static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
 {
        struct zfcp_port *port = erp_action->port;
+       int p_status = atomic_read(&port->status);
 
-       if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
+       if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
+           !(p_status & ZFCP_STATUS_COMMON_OPEN))
                goto close_init_done;
 
        switch (erp_action->step) {
        case ZFCP_ERP_STEP_UNINITIALIZED:
                zfcp_erp_port_strategy_clearstati(port);
-               if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
+               if (p_status & ZFCP_STATUS_COMMON_OPEN)
                        return zfcp_erp_port_strategy_close(erp_action);
                break;
 
        case ZFCP_ERP_STEP_PORT_CLOSING:
-               if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
+               if (p_status & ZFCP_STATUS_COMMON_OPEN)
                        return ZFCP_ERP_FAILED;
                break;
        }
@@ -1155,7 +1151,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
        }
 
        list_del(&erp_action->list);
-       zfcp_rec_dbf_event_action("eractd1", erp_action);
+       zfcp_dbf_rec_action("eractd1", erp_action);
 
        switch (erp_action->action) {
        case ZFCP_ERP_ACTION_REOPEN_UNIT:
@@ -1185,28 +1181,28 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
        switch (act->action) {
        case ZFCP_ERP_ACTION_REOPEN_UNIT:
                if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
-                       zfcp_unit_get(unit);
+                       get_device(&unit->dev);
                        if (scsi_queue_work(unit->port->adapter->scsi_host,
                                            &unit->scsi_work) <= 0)
-                               zfcp_unit_put(unit);
+                               put_device(&unit->dev);
                }
-               zfcp_unit_put(unit);
+               put_device(&unit->dev);
                break;
 
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
        case ZFCP_ERP_ACTION_REOPEN_PORT:
                if (result == ZFCP_ERP_SUCCEEDED)
                        zfcp_scsi_schedule_rport_register(port);
-               zfcp_port_put(port);
+               put_device(&port->dev);
                break;
 
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
                if (result == ZFCP_ERP_SUCCEEDED) {
                        register_service_level(&adapter->service_level);
-                       schedule_work(&adapter->scan_work);
+                       queue_work(adapter->work_queue, &adapter->scan_work);
                } else
                        unregister_service_level(&adapter->service_level);
-               zfcp_adapter_put(adapter);
+               kref_put(&adapter->ref, zfcp_adapter_release);
                break;
        }
 }
@@ -1229,12 +1225,12 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
 static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
 {
        int retval;
-       struct zfcp_adapter *adapter = erp_action->adapter;
        unsigned long flags;
+       struct zfcp_adapter *adapter = erp_action->adapter;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       write_lock(&adapter->erp_lock);
+       kref_get(&adapter->ref);
 
+       write_lock_irqsave(&adapter->erp_lock, flags);
        zfcp_erp_strategy_check_fsfreq(erp_action);
 
        if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
@@ -1246,11 +1242,9 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
        zfcp_erp_action_to_running(erp_action);
 
        /* no lock to allow for blocking operations */
-       write_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       write_unlock_irqrestore(&adapter->erp_lock, flags);
        retval = zfcp_erp_strategy_do_action(erp_action);
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       write_lock(&adapter->erp_lock);
+       write_lock_irqsave(&adapter->erp_lock, flags);
 
        if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
                retval = ZFCP_ERP_CONTINUES;
@@ -1282,15 +1276,18 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
        retval = zfcp_erp_strategy_statechange(erp_action, retval);
        if (retval == ZFCP_ERP_EXIT)
                goto unlock;
-       zfcp_erp_strategy_followup_actions(erp_action);
+       if (retval == ZFCP_ERP_SUCCEEDED)
+               zfcp_erp_strategy_followup_success(erp_action);
+       if (retval == ZFCP_ERP_FAILED)
+               zfcp_erp_strategy_followup_failed(erp_action);
 
  unlock:
-       write_unlock(&adapter->erp_lock);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       write_unlock_irqrestore(&adapter->erp_lock, flags);
 
        if (retval != ZFCP_ERP_CONTINUES)
                zfcp_erp_action_cleanup(erp_action, retval);
 
+       kref_put(&adapter->ref, zfcp_adapter_release);
        return retval;
 }
 
@@ -1300,16 +1297,17 @@ static int zfcp_erp_thread(void *data)
        struct list_head *next;
        struct zfcp_erp_action *act;
        unsigned long flags;
-       int ignore;
 
-       daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
-       /* Block all signals */
-       siginitsetinv(&current->blocked, 0);
-       atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
-       wake_up(&adapter->erp_thread_wqh);
+       for (;;) {
+               zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
+               wait_event_interruptible(adapter->erp_ready_wq,
+                          !list_empty(&adapter->erp_ready_head) ||
+                          kthread_should_stop());
+               zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
+
+               if (kthread_should_stop())
+                       break;
 
-       while (!(atomic_read(&adapter->status) &
-                ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) {
                write_lock_irqsave(&adapter->erp_lock, flags);
                next = adapter->erp_ready_head.next;
                write_unlock_irqrestore(&adapter->erp_lock, flags);
@@ -1321,15 +1319,8 @@ static int zfcp_erp_thread(void *data)
                        if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
                                zfcp_erp_wakeup(adapter);
                }
-
-               zfcp_rec_dbf_event_thread_lock("erthrd1", adapter);
-               ignore = down_interruptible(&adapter->erp_ready_sem);
-               zfcp_rec_dbf_event_thread_lock("erthrd2", adapter);
        }
 
-       atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
-       wake_up(&adapter->erp_thread_wqh);
-
        return 0;
 }
 
@@ -1341,18 +1332,17 @@ static int zfcp_erp_thread(void *data)
  */
 int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
 {
-       int retval;
+       struct task_struct *thread;
 
-       atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
-       retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
-       if (retval < 0) {
+       thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
+                            dev_name(&adapter->ccw_device->dev));
+       if (IS_ERR(thread)) {
                dev_err(&adapter->ccw_device->dev,
                        "Creating an ERP thread for the FCP device failed.\n");
-               return retval;
+               return PTR_ERR(thread);
        }
-       wait_event(adapter->erp_thread_wqh,
-                  atomic_read(&adapter->status) &
-                       ZFCP_STATUS_ADAPTER_ERP_THREAD_UP);
+
+       adapter->erp_thread = thread;
        return 0;
 }
 
@@ -1367,16 +1357,10 @@ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
  */
 void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
 {
-       atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
-       up(&adapter->erp_ready_sem);
-       zfcp_rec_dbf_event_thread_lock("erthrk1", adapter);
-
-       wait_event(adapter->erp_thread_wqh,
-                  !(atomic_read(&adapter->status) &
-                               ZFCP_STATUS_ADAPTER_ERP_THREAD_UP));
-
-       atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL,
-                         &adapter->status);
+       kthread_stop(adapter->erp_thread);
+       adapter->erp_thread = NULL;
+       WARN_ON(!list_empty(&adapter->erp_ready_head));
+       WARN_ON(!list_empty(&adapter->erp_running_head));
 }
 
 /**
@@ -1440,24 +1424,28 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
                                    void *ref, u32 mask, int set_or_clear)
 {
        struct zfcp_port *port;
+       unsigned long flags;
        u32 common_mask = mask & ZFCP_COMMON_FLAGS;
 
        if (set_or_clear == ZFCP_SET) {
                if (status_change_set(mask, &adapter->status))
-                       zfcp_rec_dbf_event_adapter(id, ref, adapter);
+                       zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
                atomic_set_mask(mask, &adapter->status);
        } else {
                if (status_change_clear(mask, &adapter->status))
-                       zfcp_rec_dbf_event_adapter(id, ref, adapter);
+                       zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
                atomic_clear_mask(mask, &adapter->status);
                if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
                        atomic_set(&adapter->erp_counter, 0);
        }
 
-       if (common_mask)
-               list_for_each_entry(port, &adapter->port_list_head, list)
+       if (common_mask) {
+               read_lock_irqsave(&adapter->port_list_lock, flags);
+               list_for_each_entry(port, &adapter->port_list, list)
                        zfcp_erp_modify_port_status(port, id, ref, common_mask,
                                                    set_or_clear);
+               read_unlock_irqrestore(&adapter->port_list_lock, flags);
+       }
 }
 
 /**
@@ -1474,24 +1462,28 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
                                 u32 mask, int set_or_clear)
 {
        struct zfcp_unit *unit;
+       unsigned long flags;
        u32 common_mask = mask & ZFCP_COMMON_FLAGS;
 
        if (set_or_clear == ZFCP_SET) {
                if (status_change_set(mask, &port->status))
-                       zfcp_rec_dbf_event_port(id, ref, port);
+                       zfcp_dbf_rec_port(id, ref, port);
                atomic_set_mask(mask, &port->status);
        } else {
                if (status_change_clear(mask, &port->status))
-                       zfcp_rec_dbf_event_port(id, ref, port);
+                       zfcp_dbf_rec_port(id, ref, port);
                atomic_clear_mask(mask, &port->status);
                if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
                        atomic_set(&port->erp_counter, 0);
        }
 
-       if (common_mask)
-               list_for_each_entry(unit, &port->unit_list_head, list)
+       if (common_mask) {
+               read_lock_irqsave(&port->unit_list_lock, flags);
+               list_for_each_entry(unit, &port->unit_list, list)
                        zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
                                                    set_or_clear);
+               read_unlock_irqrestore(&port->unit_list_lock, flags);
+       }
 }
 
 /**
@@ -1507,11 +1499,11 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
 {
        if (set_or_clear == ZFCP_SET) {
                if (status_change_set(mask, &unit->status))
-                       zfcp_rec_dbf_event_unit(id, ref, unit);
+                       zfcp_dbf_rec_unit(id, ref, unit);
                atomic_set_mask(mask, &unit->status);
        } else {
                if (status_change_clear(mask, &unit->status))
-                       zfcp_rec_dbf_event_unit(id, ref, unit);
+                       zfcp_dbf_rec_unit(id, ref, unit);
                atomic_clear_mask(mask, &unit->status);
                if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
                        atomic_set(&unit->erp_counter, 0);
@@ -1527,12 +1519,8 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
  */
 void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
 {
-       unsigned long flags;
-
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
        zfcp_erp_modify_port_status(port, id, ref,
                                    ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
        zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
 }
 
@@ -1560,13 +1548,9 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
  */
 void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
 {
-       unsigned long flags;
-
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
        zfcp_erp_modify_port_status(port, id, ref,
                                    ZFCP_STATUS_COMMON_ERP_FAILED |
                                    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
 /**
@@ -1599,12 +1583,15 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
                                         void *ref)
 {
        struct zfcp_unit *unit;
+       unsigned long flags;
        int status = atomic_read(&port->status);
 
        if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
                        ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
-               list_for_each_entry(unit, &port->unit_list_head, list)
+               read_lock_irqsave(&port->unit_list_lock, flags);
+               list_for_each_entry(unit, &port->unit_list, list)
                                    zfcp_erp_unit_access_changed(unit, id, ref);
+               read_unlock_irqrestore(&port->unit_list_lock, flags);
                return;
        }
 
@@ -1620,14 +1607,14 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
 void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
                                     void *ref)
 {
-       struct zfcp_port *port;
        unsigned long flags;
+       struct zfcp_port *port;
 
        if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
                return;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       list_for_each_entry(port, &adapter->port_list_head, list)
+       read_lock_irqsave(&adapter->port_list_lock, flags);
+       list_for_each_entry(port, &adapter->port_list, list)
                zfcp_erp_port_access_changed(port, id, ref);
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       read_unlock_irqrestore(&adapter->port_list_lock, flags);
 }