summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2008-07-02 10:56:40 +0200
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 08:22:36 -0500
commit287ac01acf22ab6aaaf9f5a4919ce2449c8b391c (patch)
treeb8ea35d04aa7d74c68739a67a9e2c8b4151c0017 /drivers/s390
parentc41f8cbddd4e0e72951e0575165dea8ea26f1c4b (diff)
[SCSI] zfcp: Cleanup code in zfcp_erp.c
Cleanup the code in zfcp_erp.c, move erp internal definititions to this file and move FSF timeout handling to the FSF layer. Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/scsi/zfcp_def.h45
-rw-r--r--drivers/s390/scsi/zfcp_erp.c3370
-rw-r--r--drivers/s390/scsi/zfcp_ext.h25
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c43
4 files changed, 1280 insertions, 2203 deletions
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 206b6e7a8bfd..67f45fc62f53 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -91,17 +91,11 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
/* max. number of (data buffer) SBALEs in largest SBAL chain
multiplied with number of sectors per 4k block */
-#define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */
-
/********************* FSF SPECIFIC DEFINES *********************************/
/* ATTENTION: value must not be used by hardware */
#define FSF_QTCB_UNSOLICITED_STATUS 0x6305
-/* Do 1st retry in 1 second, then double the timeout for each following retry */
-#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1
-#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7
-
/* timeout value for "default timer" for fsf requests */
#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ)
@@ -349,45 +343,6 @@ struct zfcp_rc_entry {
#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800
#define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000
-/*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/
-
-#define ZFCP_MAX_ERPS 3
-
-#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
-#define ZFCP_ERP_STEP_PHYS_PORT_CLOSING 0x00000010
-#define ZFCP_ERP_STEP_PORT_CLOSING 0x00000100
-#define ZFCP_ERP_STEP_NAMESERVER_OPEN 0x00000200
-#define ZFCP_ERP_STEP_NAMESERVER_LOOKUP 0x00000400
-#define ZFCP_ERP_STEP_PORT_OPENING 0x00000800
-#define ZFCP_ERP_STEP_UNIT_CLOSING 0x00001000
-#define ZFCP_ERP_STEP_UNIT_OPENING 0x00002000
-
-/* Ordered by escalation level (necessary for proper erp-code operation) */
-#define ZFCP_ERP_ACTION_REOPEN_ADAPTER 0x4
-#define ZFCP_ERP_ACTION_REOPEN_PORT_FORCED 0x3
-#define ZFCP_ERP_ACTION_REOPEN_PORT 0x2
-#define ZFCP_ERP_ACTION_REOPEN_UNIT 0x1
-
-#define ZFCP_ERP_ACTION_RUNNING 0x1
-#define ZFCP_ERP_ACTION_READY 0x2
-
-#define ZFCP_ERP_SUCCEEDED 0x0
-#define ZFCP_ERP_FAILED 0x1
-#define ZFCP_ERP_CONTINUES 0x2
-#define ZFCP_ERP_EXIT 0x3
-#define ZFCP_ERP_DISMISSED 0x4
-#define ZFCP_ERP_NOMEM 0x5
-
/************************* STRUCTURE DEFINITIONS *****************************/
struct zfcp_fsf_req;
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 4d797e5264d9..643ac4bba5b5 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -8,1345 +8,582 @@
#include "zfcp_ext.h"
-static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8,
- void *);
-static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8,
- void *);
-static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int, u8, void *);
-static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *, int, u8, void *);
-
-static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *, int, u8,
- void *);
-static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *, int, u8,
- void *);
-
-static void zfcp_erp_adapter_block(struct zfcp_adapter *, int);
-static void zfcp_erp_adapter_unblock(struct zfcp_adapter *);
-static void zfcp_erp_port_block(struct zfcp_port *, int);
-static void zfcp_erp_port_unblock(struct zfcp_port *);
-static void zfcp_erp_unit_block(struct zfcp_unit *, int);
-static void zfcp_erp_unit_unblock(struct zfcp_unit *);
-
-static int zfcp_erp_thread(void *);
-
-static int zfcp_erp_strategy(struct zfcp_erp_action *);
-
-static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *);
-static int zfcp_erp_strategy_memwait(struct zfcp_erp_action *);
-static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *, int);
-static int zfcp_erp_strategy_check_unit(struct zfcp_unit *, int);
-static int zfcp_erp_strategy_check_port(struct zfcp_port *, int);
-static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int);
-static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
- struct zfcp_port *,
- struct zfcp_unit *, int);
-static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
-static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
- struct zfcp_port *,
- struct zfcp_unit *, int);
-static int zfcp_erp_strategy_check_queues(struct zfcp_adapter *);
-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_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 *);
-static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_open_fsf_statusread(
- struct zfcp_erp_action *);
-
-static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *);
-static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *);
-
-static int zfcp_erp_port_strategy(struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_clearstati(struct zfcp_port *);
-static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_open_nameserver_wakeup(
- struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *);
-static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *);
-
-static int zfcp_erp_unit_strategy(struct zfcp_erp_action *);
-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 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 *,
- u8 id, void *ref);
-static int zfcp_erp_action_dequeue(struct zfcp_erp_action *);
-static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
- struct zfcp_port *, struct zfcp_unit *,
- int);
-
-static void zfcp_erp_action_ready(struct zfcp_erp_action *);
-static int zfcp_erp_action_exists(struct zfcp_erp_action *);
-
-static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
-
-static void zfcp_erp_memwait_handler(unsigned long);
+#define ZFCP_MAX_ERPS 3
+
+enum zfcp_erp_act_flags {
+ ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000,
+ ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000,
+ ZFCP_STATUS_ERP_DISMISSING = 0x00100000,
+ ZFCP_STATUS_ERP_DISMISSED = 0x00200000,
+ ZFCP_STATUS_ERP_LOWMEM = 0x00400000,
+};
-/**
- * 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_qdio_close(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, 24, NULL,
- ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
-}
+enum zfcp_erp_steps {
+ ZFCP_ERP_STEP_UNINITIALIZED = 0x0000,
+ ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001,
+ ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
+ ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
+ ZFCP_ERP_STEP_NAMESERVER_OPEN = 0x0200,
+ ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400,
+ ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
+ ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
+ ZFCP_ERP_STEP_UNIT_OPENING = 0x2000,
+};
-/**
- * zfcp_fsf_request_timeout_handler - called if a request timed out
- * @data: pointer to adapter for handler function
- *
- * 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.
- */
-static void zfcp_fsf_request_timeout_handler(unsigned long data)
-{
- struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
- zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62,
- NULL);
-}
+enum zfcp_erp_act_type {
+ ZFCP_ERP_ACTION_REOPEN_UNIT = 1,
+ ZFCP_ERP_ACTION_REOPEN_PORT = 2,
+ ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
+ ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4,
+};
+
+enum zfcp_erp_act_state {
+ ZFCP_ERP_ACTION_RUNNING = 1,
+ ZFCP_ERP_ACTION_READY = 2,
+};
-void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
+enum zfcp_erp_act_result {
+ ZFCP_ERP_SUCCEEDED = 0,
+ ZFCP_ERP_FAILED = 1,
+ ZFCP_ERP_CONTINUES = 2,
+ ZFCP_ERP_EXIT = 3,
+ ZFCP_ERP_DISMISSED = 4,
+ ZFCP_ERP_NOMEM = 5,
+};
+
+static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
{
- fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
- fsf_req->timer.data = (unsigned long) fsf_req->adapter;
- fsf_req->timer.expires = jiffies + timeout;
- add_timer(&fsf_req->timer);
+ zfcp_erp_modify_adapter_status(adapter, 15, NULL,
+ ZFCP_STATUS_COMMON_UNBLOCKED | mask,
+ ZFCP_CLEAR);
}
-/*
- * function:
- *
- * purpose: called if an adapter failed,
- * initiates adapter recovery which is done
- * asynchronously
- *
- * returns: 0 - initiated action successfully
- * <0 - failed to initiate action
- */
-static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter,
- int clear_mask, u8 id, void *ref)
+static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
{
- int retval;
-
- zfcp_erp_adapter_block(adapter, clear_mask);
+ struct zfcp_erp_action *curr_act;
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) {
- /* ensure propagation of failed status to new devices */
- zfcp_erp_adapter_failed(adapter, 13, NULL);
- retval = -EIO;
- goto out;
- }
- retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
- adapter, NULL, NULL, id, ref);
-
- out:
- return retval;
+ list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
+ if (act == curr_act)
+ return ZFCP_ERP_ACTION_RUNNING;
+ return 0;
}
-/*
- * function:
- *
- * purpose: Wrappper for zfcp_erp_adapter_reopen_internal
- * used to ensure the correct locking
- *
- * returns: 0 - initiated action successfully
- * <0 - failed to initiate action
- */
-int zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask,
- u8 id, void *ref)
+static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
{
- int retval;
- unsigned long flags;
+ struct zfcp_adapter *adapter = act->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
- retval = zfcp_erp_adapter_reopen_internal(adapter, clear_mask, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-
- return retval;
+ list_move(&act->list, &act->adapter->erp_ready_head);
+ zfcp_rec_dbf_event_action(146, act);
+ up(&adapter->erp_ready_sem);
+ zfcp_rec_dbf_event_thread(2, adapter);
}
-int zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask,
- u8 id, void *ref)
+static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
{
- int retval;
-
- retval = zfcp_erp_adapter_reopen(adapter,
- ZFCP_STATUS_COMMON_RUNNING |
- ZFCP_STATUS_COMMON_ERP_FAILED |
- clear_mask, id, ref);
-
- return retval;
+ act->status |= ZFCP_STATUS_ERP_DISMISSED;
+ if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
+ zfcp_erp_action_ready(act);
}
-int zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask, u8 id,
- void *ref)
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
{
- int retval;
+ if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
+ zfcp_erp_action_dismiss(&unit->erp_action);
+}
- retval = zfcp_erp_port_reopen(port,
- ZFCP_STATUS_COMMON_RUNNING |
- ZFCP_STATUS_COMMON_ERP_FAILED |
- clear_mask, id, ref);
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
+{
+ struct zfcp_unit *unit;
- return retval;
+ 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);
}
-int zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask, u8 id,
- void *ref)
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
{
- int retval;
-
- retval = zfcp_erp_unit_reopen(unit,
- ZFCP_STATUS_COMMON_RUNNING |
- ZFCP_STATUS_COMMON_ERP_FAILED |
- clear_mask, id, ref);
+ struct zfcp_port *port;
- return retval;
+ 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)
+ zfcp_erp_action_dismiss_port(port);
}
-/*
- * function:
- *
- * purpose: called if a port failed to be opened normally
- * initiates Forced Reopen recovery which is done
- * asynchronously
- *
- * returns: 0 - initiated action successfully
- * <0 - failed to initiate action
- */
-static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port,
- int clear_mask, u8 id,
- void *ref)
+static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
+ struct zfcp_port *port,
+ struct zfcp_unit *unit)
{
- int retval;
-
- zfcp_erp_port_block(port, clear_mask);
+ int need = want;
+ int u_status, p_status, a_status;
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
- retval = -EIO;
- goto out;
+ switch (want) {
+ case ZFCP_ERP_ACTION_REOPEN_UNIT:
+ u_status = atomic_read(&unit->status);
+ if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
+ return 0;
+ p_status = atomic_read(&port->status);
+ if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
+ p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
+ return 0;
+ if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
+ need = ZFCP_ERP_ACTION_REOPEN_PORT;
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+ p_status = atomic_read(&port->status);
+ if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
+ return 0;
+ a_status = atomic_read(&adapter->status);
+ if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
+ a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
+ return 0;
+ if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
+ need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+ a_status = atomic_read(&adapter->status);
+ if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
+ return 0;
}
- retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
- port->adapter, port, NULL, id, ref);
-
- out:
- return retval;
+ return need;
}
-/*
- * function:
- *
- * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal
- * used to ensure the correct locking
- *
- * returns: 0 - initiated action successfully
- * <0 - failed to initiate action
- */
-int zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask, u8 id,
- void *ref)
+static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
+ struct zfcp_adapter *adapter,
+ struct zfcp_port *port,
+ struct zfcp_unit *unit)
{
- int retval;
- unsigned long flags;
- struct zfcp_adapter *adapter;
-
- adapter = port->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
- retval = zfcp_erp_port_forced_reopen_internal(port, clear_mask, id,
- ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ struct zfcp_erp_action *erp_action;
+ u32 status = 0;
- return retval;
-}
+ switch (need) {
+ case ZFCP_ERP_ACTION_REOPEN_UNIT:
+ zfcp_unit_get(unit);
+ atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
+ erp_action = &unit->erp_action;
+ if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
+ status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ break;
-/*
- * function:
- *
- * purpose: called if a port is to be opened
- * initiates Reopen recovery which is done
- * asynchronously
- *
- * returns: 0 - initiated action successfully
- * <0 - failed to initiate action
- */
-static int zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask,
- u8 id, void *ref)
-{
- int retval;
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+ zfcp_port_get(port);
+ zfcp_erp_action_dismiss_port(port);
+ atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
+ erp_action = &port->erp_action;
+ if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
+ status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ break;
- zfcp_erp_port_block(port, clear_mask);
+ case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+ zfcp_adapter_get(adapter);
+ zfcp_erp_action_dismiss_adapter(adapter);
+ atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
+ erp_action = &adapter->erp_action;
+ if (!(atomic_read(&adapter->status) &
+ ZFCP_STATUS_COMMON_RUNNING))
+ status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ break;
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
- /* ensure propagation of failed status to new devices */
- zfcp_erp_port_failed(port, 14, NULL);
- retval = -EIO;
- goto out;
+ default:
+ return NULL;
}
- retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
- port->adapter, port, NULL, id, ref);
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->adapter = adapter;
+ erp_action->port = port;
+ erp_action->unit = unit;
+ erp_action->action = need;
+ erp_action->status = status;
- out:
- return retval;
+ return erp_action;
}
-/**
- * zfcp_erp_port_reopen - initiate reopen of a remote port
- * @port: port to be reopened
- * @clear_mask: specifies flags in port status to be cleared
- * Return: 0 on success, < 0 on error
- *
- * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures
- * correct locking. An error recovery task is initiated to do the reopen.
- * To wait for the completion of the reopen zfcp_erp_wait should be used.
- */
-int zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask, u8 id,
- void *ref)
+static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
+ struct zfcp_port *port,
+ struct zfcp_unit *unit, u8 id, void *ref)
{
- int retval;
- unsigned long flags;
- struct zfcp_adapter *adapter = port->adapter;
+ int retval = 1, need;
+ struct zfcp_erp_action *act = NULL;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
- retval = zfcp_erp_port_reopen_internal(port, clear_mask, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ if (!(atomic_read(&adapter->status) &
+ ZFCP_STATUS_ADAPTER_ERP_THREAD_UP))
+ return -EIO;
+
+ need = zfcp_erp_required_act(want, adapter, port, unit);
+ if (!need)
+ goto out;
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
+ act = zfcp_erp_setup_act(need, adapter, port, unit);
+ if (!act)
+ 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(1, adapter);
+ retval = 0;
+ out:
+ zfcp_rec_dbf_event_trigger(id, ref, want, need, act,
+ adapter, port, unit);
return retval;
}
-/*
- * function:
- *
- * purpose: called if a unit is to be opened
- * initiates Reopen recovery which is done
- * asynchronously
- *
- * returns: 0 - initiated action successfully
- * <0 - failed to initiate action
- */
-static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask,
- u8 id, void *ref)
+static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
+ int clear_mask, u8 id, void *ref)
{
- int retval;
- struct zfcp_adapter *adapter = unit->port->adapter;
-
- zfcp_erp_unit_block(unit, clear_mask);
+ zfcp_erp_adapter_block(adapter, clear_mask);
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) {
- retval = -EIO;
- goto out;
+ /* ensure propagation of failed status to new devices */
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
+ zfcp_erp_adapter_failed(adapter, 13, NULL);
+ return -EIO;
}
-
- retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
- adapter, unit->port, unit, id, ref);
- out:
- return retval;
+ return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
+ adapter, NULL, NULL, id, ref);
}
/**
- * zfcp_erp_unit_reopen - initiate reopen of a unit
- * @unit: unit to be reopened
- * @clear_mask: specifies flags in unit status to be cleared
- * Return: 0 on success, < 0 on error
- *
- * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct
- * locking. An error recovery task is initiated to do the reopen.
- * To wait for the completion of the reopen zfcp_erp_wait should be used.
+ * zfcp_erp_adapter_reopen - Reopen adapter.
+ * @adapter: Adapter to reopen.
+ * @clear: Status flags to clear.
+ * @id: Id for debug trace event.
+ * @ref: Reference for debug trace event.
*/
-int zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask, u8 id,
- void *ref)
+void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
+ u8 id, void *ref)
{
- int retval;
unsigned long flags;
- struct zfcp_adapter *adapter;
- struct zfcp_port *port;
-
- port = unit->port;
- adapter = port->adapter;
read_lock_irqsave(&zfcp_data.config_lock, flags);
write_lock(&adapter->erp_lock);
- retval = zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref);
+ _zfcp_erp_adapter_reopen(adapter, clear, id, ref);
write_unlock(&adapter->erp_lock);
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-
- return retval;
}
/**
- * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests
+ * zfcp_erp_adapter_shutdown - Shutdown adapter.
+ * @adapter: Adapter to shut down.
+ * @clear: Status flags to clear.
+ * @id: Id for debug trace event.
+ * @ref: Reference for debug trace event.
*/
-static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
+void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
+ u8 id, void *ref)
{
- zfcp_erp_modify_adapter_status(adapter, 15, NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED |
- clear_mask, ZFCP_CLEAR);
+ int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
+ zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
}
-/* FIXME: isn't really atomic */
-/*
- * returns the mask which has not been set so far, i.e.
- * 0 if no bit has been changed, !0 if some bit has been changed
- */
-static int atomic_test_and_set_mask(unsigned long mask, atomic_t *v)
-{
- int changed_bits = (atomic_read(v) /*XOR*/^ mask) & mask;
- atomic_set_mask(mask, v);
- return changed_bits;
-}
-
-/* FIXME: isn't really atomic */
-/*
- * returns the mask which has not been cleared so far, i.e.
- * 0 if no bit has been changed, !0 if some bit has been changed
+/**
+ * zfcp_erp_port_shutdown - Shutdown port
+ * @port: Port to shut down.
+ * @clear: Status flags to clear.
+ * @id: Id for debug trace event.
+ * @ref: Reference for debug trace event.
*/
-static int atomic_test_and_clear_mask(unsigned long mask, atomic_t *v)
+void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref)
{
- int changed_bits = atomic_read(v) & mask;
- atomic_clear_mask(mask, v);
- return changed_bits;
+ int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
+ zfcp_erp_port_reopen(port, clear | flags, id, ref);
}
/**
- * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests
+ * zfcp_erp_unit_shutdown - Shutdown unit
+ * @unit: Unit to shut down.
+ * @clear: Status flags to clear.
+ * @id: Id for debug trace event.
+ * @ref: Reference for debug trace event.
*/
-static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
+void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref)
{
- if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
- &adapter->status))
- zfcp_rec_dbf_event_adapter(16, NULL, adapter);
+ int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
+ zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
}
-/*
- * function:
- *
- * purpose: disable I/O,
- * return any open requests and clean them up,
- * aim: no pending and incoming I/O
- *
- * returns:
- */
-static void
-zfcp_erp_port_block(struct zfcp_port *port, int clear_mask)
+static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
{
zfcp_erp_modify_port_status(port, 17, NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
+ ZFCP_STATUS_COMMON_UNBLOCKED | clear,
ZFCP_CLEAR);
}
-/*
- * function:
- *
- * purpose: enable I/O
- *
- * returns:
- */
-static void
-zfcp_erp_port_unblock(struct zfcp_port *port)
+static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
+ int clear, u8 id, void *ref)
{
- if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
- &port->status))
- zfcp_rec_dbf_event_port(18, NULL, port);
-}
+ zfcp_erp_port_block(port, clear);
-/*
- * function:
- *
- * purpose: disable I/O,
- * return any open requests and clean them up,
- * aim: no pending and incoming I/O
- *
- * returns:
- */
-static void
-zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
-{
- zfcp_erp_modify_unit_status(unit, 19, NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
- ZFCP_CLEAR);
-}
-
-/*
- * function:
- *
- * purpose: enable I/O
- *
- * returns:
- */
-static void
-zfcp_erp_unit_unblock(struct zfcp_unit *unit)
-{
- if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
- &unit->status))
- zfcp_rec_dbf_event_unit(20, NULL, unit);
-}
-
-static void
-zfcp_erp_action_ready(struct zfcp_erp_action *erp_action)
-{
- struct zfcp_adapter *adapter = erp_action->adapter;
-
- zfcp_erp_action_to_ready(erp_action);
- up(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread(2, adapter);
-}
-
-/*
- * function:
- *
- * purpose:
- *
- * returns: <0 erp_action not found in any list
- * ZFCP_ERP_ACTION_READY erp_action is in ready list
- * ZFCP_ERP_ACTION_RUNNING erp_action is in running list
- *
- * locks: erp_lock must be held
- */
-static int
-zfcp_erp_action_exists(struct zfcp_erp_action *erp_action)
-{
- int retval = -EINVAL;
- struct list_head *entry;
- struct zfcp_erp_action *entry_erp_action;
- struct zfcp_adapter *adapter = erp_action->adapter;
-
- /* search in running list */
- list_for_each(entry, &adapter->erp_running_head) {
- entry_erp_action =
- list_entry(entry, struct zfcp_erp_action, list);
- if (entry_erp_action == erp_action) {
- retval = ZFCP_ERP_ACTION_RUNNING;
- goto out;
- }
- }
- /* search in ready list */
- list_for_each(entry, &adapter->erp_ready_head) {
- entry_erp_action =
- list_entry(entry, struct zfcp_erp_action, list);
- if (entry_erp_action == erp_action) {
- retval = ZFCP_ERP_ACTION_READY;
- goto out;
- }
- }
-
- out:
- return retval;
-}
-
-/*
- * purpose: checks current status of action (timed out, dismissed, ...)
- * and does appropriate preparations (dismiss fsf request, ...)
- *
- * locks: called under erp_lock (disabled interrupts)
- */
-static void
-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 deleted meanwhile */
- spin_lock(&adapter->req_list_lock);
- if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) &&
- erp_action->fsf_req->erp_action == erp_action) {
- /* fsf_req still exists */
- /* dismiss fsf_req of timed out/dismissed erp_action */
- if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED |
- ZFCP_STATUS_ERP_TIMEDOUT)) {
- erp_action->fsf_req->status |=
- ZFCP_STATUS_FSFREQ_DISMISSED;
- zfcp_rec_dbf_event_action(142, erp_action);
- }
- if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
- zfcp_rec_dbf_event_action(143, erp_action);
- /*
- * 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.
- */
- if (erp_action->fsf_req->status &
- (ZFCP_STATUS_FSFREQ_COMPLETED |
- ZFCP_STATUS_FSFREQ_DISMISSED)) {
- /* forget about association between fsf_req
- and erp_action */
- erp_action->fsf_req = NULL;
- }
- } else {
- /*
- * even if this fsf_req has gone, forget about
- * association between erp_action and fsf_req
- */
- erp_action->fsf_req = NULL;
- }
- spin_unlock(&adapter->req_list_lock);
- }
-}
+ if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+ return;
-/**
- * zfcp_erp_async_handler_nolock - complete erp_action
- *
- * Used for normal completion, time-out, dismissal and failure after
- * low memory condition.
- */
-static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
- unsigned long set_mask)
-{
- if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
- erp_action->status |= set_mask;
- zfcp_erp_action_ready(erp_action);
- } else {
- /* action is ready or gone - nothing to do */
- }
+ zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
+ port->adapter, port, NULL, id, ref);
}
/**
- * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking
+ * zfcp_erp_port_forced_reopen - Forced close of port and open again
+ * @port: Port to force close and to reopen.
+ * @id: Id for debug trace event.
+ * @ref: Reference for debug trace event.
*/
-void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
- unsigned long set_mask)
+void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id,
+ void *ref)
{
- struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long flags;
+ struct zfcp_adapter *adapter = port->adapter;
- write_lock_irqsave(&adapter->erp_lock, flags);
- zfcp_erp_async_handler_nolock(erp_action, set_mask);
- write_unlock_irqrestore(&adapter->erp_lock, flags);
+ read_lock_irqsave(&zfcp_data.config_lock, flags);
+ write_lock(&adapter->erp_lock);
+ _zfcp_erp_port_forced_reopen(port, clear, id, ref);
+ write_unlock(&adapter->erp_lock);
+ read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
-/*
- * purpose: is called for erp_action which was slept waiting for
- * memory becoming avaliable,
- * will trigger that this action will be continued
- */
-static void
-zfcp_erp_memwait_handler(unsigned long data)
+static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id,
+ void *ref)
{
- struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
-
- zfcp_erp_async_handler(erp_action, 0);
-}
+ zfcp_erp_port_block(port, clear);
-/*
- * purpose: is called if an asynchronous erp step timed out,
- * action gets an appropriate flag and will be processed
- * accordingly
- */
-static void zfcp_erp_timeout_handler(unsigned long data)
-{
- struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
+ if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
+ /* ensure propagation of failed status to new devices */
+ zfcp_erp_port_failed(port, 14, NULL);
+ return -EIO;
+ }
- zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT);
+ return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
+ port->adapter, port, NULL, id, ref);
}
/**
- * zfcp_erp_action_dismiss - dismiss an erp_action
+ * zfcp_erp_port_reopen - trigger remote port recovery
+ * @port: port to recover
+ * @clear_mask: flags in port status to be cleared
*
- * adapter->erp_lock must be held
- *
- * Dismissal of an erp_action is usually required if an erp_action of
- * higher priority is generated.
+ * Returns 0 if recovery has been triggered, < 0 if not.
*/
-static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
-{
- erp_action->status |= ZFCP_STATUS_ERP_DISMISSED;
- if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING)
- zfcp_erp_action_ready(erp_action);
-}
-
-int
-zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
+int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref)
{
- int retval = 0;
-
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
+ unsigned long flags;
+ int retval;
+ struct zfcp_adapter *adapter = port->adapter;
- retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
- if (retval < 0)
- dev_err(&adapter->ccw_device->dev,
- "Creation of ERP thread failed.\n");
- else {
- wait_event(adapter->erp_thread_wqh,
- atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP,
- &adapter->status));
- }
+ read_lock_irqsave(&zfcp_data.config_lock, flags);
+ write_lock(&adapter->erp_lock);
+ retval = _zfcp_erp_port_reopen(port, clear, id, ref);
+ write_unlock(&adapter->e