aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/scsi/zfcp_erp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/scsi/zfcp_erp.c')
-rw-r--r--drivers/s390/scsi/zfcp_erp.c1313
1 files changed, 549 insertions, 764 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 643ac4bba5b..c82fe65c412 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -3,10 +3,15 @@
*
* Error Recovery Procedures (ERP).
*
- * Copyright IBM Corporation 2002, 2008
+ * Copyright IBM Corp. 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
@@ -16,6 +21,7 @@ enum zfcp_erp_act_flags {
ZFCP_STATUS_ERP_DISMISSING = 0x00100000,
ZFCP_STATUS_ERP_DISMISSED = 0x00200000,
ZFCP_STATUS_ERP_LOWMEM = 0x00400000,
+ ZFCP_STATUS_ERP_NO_REF = 0x00800000,
};
enum zfcp_erp_steps {
@@ -23,15 +29,13 @@ 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_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_ERP_STEP_LUN_CLOSING = 0x1000,
+ ZFCP_ERP_STEP_LUN_OPENING = 0x2000,
};
enum zfcp_erp_act_type {
- ZFCP_ERP_ACTION_REOPEN_UNIT = 1,
+ ZFCP_ERP_ACTION_REOPEN_LUN = 1,
ZFCP_ERP_ACTION_REOPEN_PORT = 2,
ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4,
@@ -53,9 +57,8 @@ enum zfcp_erp_act_result {
static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
{
- zfcp_erp_modify_adapter_status(adapter, 15, NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | mask,
- ZFCP_CLEAR);
+ zfcp_erp_clear_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_UNBLOCKED | mask);
}
static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
@@ -73,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(146, act);
- up(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread(2, adapter);
+ zfcp_dbf_rec_run("erardy1", act);
+ wake_up(&adapter->erp_ready_wq);
+ zfcp_dbf_rec_run("erardy2", act);
}
static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
@@ -85,21 +88,27 @@ static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
zfcp_erp_action_ready(act);
}
-static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
+static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev)
{
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
- zfcp_erp_action_dismiss(&unit->erp_action);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
+ zfcp_erp_action_dismiss(&zfcp_sdev->erp_action);
}
static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
{
- struct zfcp_unit *unit;
+ struct scsi_device *sdev;
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 {
+ spin_lock(port->adapter->scsi_host->host_lock);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
+ if (sdev_to_zfcp(sdev)->port == port)
+ zfcp_erp_action_dismiss_lun(sdev);
+ spin_unlock(port->adapter->scsi_host->host_lock);
+ }
}
static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
@@ -108,22 +117,27 @@ 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,
struct zfcp_port *port,
- struct zfcp_unit *unit)
+ struct scsi_device *sdev)
{
int need = want;
- int u_status, p_status, a_status;
+ int l_status, p_status, a_status;
+ struct zfcp_scsi_dev *zfcp_sdev;
switch (want) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- u_status = atomic_read(&unit->status);
- if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ l_status = atomic_read(&zfcp_sdev->status);
+ if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0;
p_status = atomic_read(&port->status);
if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
@@ -132,15 +146,21 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
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_OPEN))
+ need = ZFCP_ERP_ACTION_REOPEN_PORT;
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ 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 (p_status & ZFCP_STATUS_COMMON_NOESC)
+ return need;
if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
/* fall through */
@@ -148,104 +168,116 @@ 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;
}
-static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
+static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
struct zfcp_adapter *adapter,
struct zfcp_port *port,
- struct zfcp_unit *unit)
+ struct scsi_device *sdev)
{
struct zfcp_erp_action *erp_action;
- u32 status = 0;
+ struct zfcp_scsi_dev *zfcp_sdev;
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;
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
+ if (scsi_device_get(sdev))
+ return NULL;
+ atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
+ &zfcp_sdev->status);
+ erp_action = &zfcp_sdev->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->port = port;
+ erp_action->sdev = sdev;
+ if (!(atomic_read(&zfcp_sdev->status) &
+ ZFCP_STATUS_COMMON_RUNNING))
+ act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
break;
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;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->port = port;
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
- status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
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;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING))
- status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
break;
default:
return NULL;
}
- 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;
+ erp_action->status = act_status;
return erp_action;
}
static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
struct zfcp_port *port,
- struct zfcp_unit *unit, u8 id, void *ref)
+ struct scsi_device *sdev,
+ char *id, u32 act_status)
{
int retval = 1, need;
- struct zfcp_erp_action *act = NULL;
+ struct zfcp_erp_action *act;
- 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);
+ need = zfcp_erp_required_act(want, adapter, port, sdev);
if (!need)
goto out;
- atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
- act = zfcp_erp_setup_act(need, adapter, port, unit);
+ act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
if (!act)
goto out;
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
++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);
+ wake_up(&adapter->erp_ready_wq);
retval = 0;
out:
- zfcp_rec_dbf_event_trigger(id, ref, want, need, act,
- adapter, port, unit);
+ zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need);
return retval;
}
static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
- int clear_mask, u8 id, void *ref)
+ int clear_mask, char *id)
{
zfcp_erp_adapter_block(adapter, clear_mask);
+ zfcp_scsi_schedule_rports_block(adapter);
/* 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);
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
return -EIO;
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
- adapter, NULL, NULL, id, ref);
+ adapter, NULL, NULL, id, 0);
}
/**
@@ -253,18 +285,22 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
* @adapter: Adapter to reopen.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
- u8 id, void *ref)
+void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id)
{
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_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
+ else
+ zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
+ NULL, NULL, id, 0);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
}
/**
@@ -272,13 +308,12 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
* @adapter: Adapter to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
- u8 id, void *ref)
+ char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
+ zfcp_erp_adapter_reopen(adapter, clear | flags, id);
}
/**
@@ -286,202 +321,220 @@ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
* @port: Port to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref)
+void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_port_reopen(port, clear | flags, id, ref);
-}
-
-/**
- * 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.
- */
-void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref)
-{
- int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
+ zfcp_erp_port_reopen(port, clear | flags, id);
}
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,
- ZFCP_CLEAR);
+ zfcp_erp_clear_port_status(port,
+ ZFCP_STATUS_COMMON_UNBLOCKED | clear);
}
-static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
- int clear, u8 id, void *ref)
+static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
+ char *id)
{
zfcp_erp_port_block(port, clear);
+ zfcp_scsi_schedule_rport_block(port);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
return;
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
- port->adapter, port, NULL, id, ref);
+ port->adapter, port, NULL, id, 0);
}
/**
* zfcp_erp_port_forced_reopen - Forced close of port and open again
* @port: Port to force close and to reopen.
+ * @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id,
- void *ref)
+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);
- _zfcp_erp_port_forced_reopen(port, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_lock_irqsave(&adapter->erp_lock, flags);
+ _zfcp_erp_port_forced_reopen(port, clear, id);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id,
- void *ref)
+static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)
{
zfcp_erp_port_block(port, clear);
+ zfcp_scsi_schedule_rport_block(port);
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);
+ zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
return -EIO;
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
- port->adapter, port, NULL, id, ref);
+ port->adapter, port, NULL, id, 0);
}
/**
* zfcp_erp_port_reopen - trigger remote port recovery
* @port: port to recover
* @clear_mask: flags in port status to be cleared
+ * @id: Id for debug trace event.
*
* Returns 0 if recovery has been triggered, < 0 if not.
*/
-int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref)
+int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)
{
- 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);
- retval = _zfcp_erp_port_reopen(port, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_lock_irqsave(&adapter->erp_lock, flags);
+ retval = _zfcp_erp_port_reopen(port, clear, id);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
return retval;
}
-static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
+static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
{
- zfcp_erp_modify_unit_status(unit, 19, NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
- ZFCP_CLEAR);
+ zfcp_erp_clear_lun_status(sdev,
+ ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask);
}
-static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id,
- void *ref)
+static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
+ u32 act_status)
{
- struct zfcp_adapter *adapter = unit->port->adapter;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
- zfcp_erp_unit_block(unit, clear);
+ zfcp_erp_lun_block(sdev, clear);
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
return;
- zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
- adapter, unit->port, unit, id, ref);
+ zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
+ zfcp_sdev->port, sdev, id, act_status);
}
/**
- * zfcp_erp_unit_reopen - initiate reopen of a unit
- * @unit: unit to be reopened
- * @clear_mask: specifies flags in unit status to be cleared
+ * zfcp_erp_lun_reopen - initiate reopen of a LUN
+ * @sdev: SCSI device / LUN to be reopened
+ * @clear_mask: specifies flags in LUN status to be cleared
+ * @id: Id for debug trace event.
+ *
* Return: 0 on success, < 0 on error
*/
-void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, void *ref)
+void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id)
{
unsigned long flags;
- struct zfcp_port *port = unit->port;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_port *port = zfcp_sdev->port;
struct zfcp_adapter *adapter = port->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
- _zfcp_erp_unit_reopen(unit, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_lock_irqsave(&adapter->erp_lock, flags);
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int status_change_set(unsigned long mask, atomic_t *status)
+/**
+ * zfcp_erp_lun_shutdown - Shutdown LUN
+ * @sdev: SCSI device / LUN to shut down.
+ * @clear: Status flags to clear.
+ * @id: Id for debug trace event.
+ */
+void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id)
{
- return (atomic_read(status) ^ mask) & mask;
+ int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
+ zfcp_erp_lun_reopen(sdev, clear | flags, id);
+}
+
+/**
+ * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
+ * @sdev: SCSI device / LUN to shut down.
+ * @id: Id for debug trace event.
+ *
+ * Do not acquire a reference for the LUN when creating the ERP
+ * action. It is safe, because this function waits for the ERP to
+ * complete first. This allows to shutdown the LUN, even when the SCSI
+ * device is in the state SDEV_DEL when scsi_device_get will fail.
+ */
+void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)
+{
+ unsigned long flags;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_port *port = zfcp_sdev->port;
+ struct zfcp_adapter *adapter = port->adapter;
+ int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
+
+ write_lock_irqsave(&adapter->erp_lock, flags);
+ _zfcp_erp_lun_reopen(sdev, clear, id, ZFCP_STATUS_ERP_NO_REF);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
+
+ zfcp_erp_wait(adapter);
}
-static int status_change_clear(unsigned long mask, atomic_t *status)
+static int status_change_set(unsigned long mask, atomic_t *status)
{
- return atomic_read(status) & mask;
+ return (atomic_read(status) ^ mask) & mask;
}
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(16, NULL, adapter);
+ zfcp_dbf_rec_run("eraubl1", &adapter->erp_action);
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(18, NULL, port);
+ zfcp_dbf_rec_run("erpubl1", &port->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
}
-static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
+static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
{
- if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
- zfcp_rec_dbf_event_unit(20, NULL, unit);
- atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
+ if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
+ zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action);
+ atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->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(145, erp_action);
+ zfcp_dbf_rec_run("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(142, act);
+ req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
+ zfcp_dbf_rec_run("erscf_1", act);
+ req->erp_action = NULL;
}
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
- zfcp_rec_dbf_event_action(143, act);
- if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
- ZFCP_STATUS_FSFREQ_DISMISSED))
- act->fsf_req = NULL;
+ zfcp_dbf_rec_run("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);
}
/**
@@ -527,58 +580,57 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
}
static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
- int clear, u8 id, void *ref)
+ int clear, char *id)
{
struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA))
- _zfcp_erp_port_reopen(port, clear, id, ref);
+ read_lock(&adapter->port_list_lock);
+ list_for_each_entry(port, &adapter->port_list, list)
+ _zfcp_erp_port_reopen(port, clear, id);
+ read_unlock(&adapter->port_list_lock);
}
-static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id,
- void *ref)
+static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
+ char *id)
{
- struct zfcp_unit *unit;
+ struct scsi_device *sdev;
- list_for_each_entry(unit, &port->unit_list_head, list)
- _zfcp_erp_unit_reopen(unit, clear, id, ref);
+ spin_lock(port->adapter->scsi_host->host_lock);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
+ if (sdev_to_zfcp(sdev)->port == port)
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
+ spin_unlock(port->adapter->scsi_host->host_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, 70, NULL);
- else
- _zfcp_erp_adapter_reopen(adapter, 0, 71, NULL);
+ _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1");
break;
-
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen(port, 0, 72, NULL);
- else
- _zfcp_erp_adapter_reopen(adapter, 0, 73, NULL);
+ _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2");
break;
-
case ZFCP_ERP_ACTION_REOPEN_PORT:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_unit_reopen_all(port, 0, 74, NULL);
- else
- _zfcp_erp_port_forced_reopen(port, 0, 75, NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersff_3");
break;
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);
+ break;
+ }
+}
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (status != ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen(unit->port, 0, 76, NULL);
+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");
+ break;
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+ _zfcp_erp_port_reopen(act->port, 0, "ersfs_2");
+ break;
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");
break;
}
}
@@ -587,25 +639,14 @@ 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);
-}
-
-static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
-{
- if (zfcp_qdio_open(act->adapter))
- return ZFCP_ERP_FAILED;
- init_waitqueue_head(&act->adapter->request_wq);
- atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
- return ZFCP_ERP_SUCCEEDED;
+ read_unlock_irqrestore(&adapter->erp_lock, flags);
}
static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
@@ -615,7 +656,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
adapter->peer_d_id);
if (IS_ERR(port)) /* error or port already attached */
return;
- _zfcp_erp_port_reopen(port, 0, 150, NULL);
+ _zfcp_erp_port_reopen(port, 0, "ereptp1");
}
static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
@@ -638,9 +679,8 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED;
}
- zfcp_rec_dbf_event_thread_lock(6, adapter);
- down(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread_lock(7, adapter);
+ wait_event(adapter->erp_ready_wq,
+ !list_empty(&adapter->erp_ready_head));
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
break;
@@ -669,8 +709,6 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
int ret;
struct zfcp_adapter *adapter = act->adapter;
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
-
write_lock_irq(&adapter->erp_lock);
zfcp_erp_action_to_running(act);
write_unlock_irq(&adapter->erp_lock);
@@ -681,9 +719,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(8, adapter);
- down(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread_lock(9, adapter);
+ zfcp_dbf_rec_run("erasox1", act);
+ wait_event(adapter->erp_ready_wq,
+ !list_empty(&adapter->erp_ready_head));
+ zfcp_dbf_rec_run("erasox2", act);
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
return ZFCP_ERP_FAILED;
@@ -698,73 +737,74 @@ 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);
+ if (mempool_resize(act->adapter->pool.sr_data,
+ act->adapter->stat_read_buf_num, GFP_KERNEL))
+ return ZFCP_ERP_FAILED;
+
+ if (mempool_resize(act->adapter->pool.status_read_req,
+ act->adapter->stat_read_buf_num, GFP_KERNEL))
+ return ZFCP_ERP_FAILED;
+
+ atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
if (zfcp_status_read_refill(act->adapter))
return ZFCP_ERP_FAILED;
return ZFCP_ERP_SUCCEEDED;
}
-static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act,
- int close)
+static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
{
- int retval = ZFCP_ERP_SUCCEEDED;
struct zfcp_adapter *adapter = act->adapter;
- if (close)
- goto close_only;
+ /* close queues to ensure that buffers are not accessed by 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 LUNs are closed */
+ zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN);
- retval = zfcp_erp_adapter_strategy_open_qdio(act);
- if (retval != ZFCP_ERP_SUCCEEDED)
- goto failed_qdio;
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
+}
- retval = zfcp_erp_adapter_strategy_open_fsf(act);
- if (retval != ZFCP_ERP_SUCCEEDED)
- goto failed_openfcp;
+static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
+{
+ struct zfcp_adapter *adapter = act->adapter;
- atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status);
- schedule_work(&act->adapter->scan_work);
+ if (zfcp_qdio_open(adapter->qdio)) {
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+ &adapter->status);
+ return ZFCP_ERP_FAILED;
+ }
- return ZFCP_ERP_SUCCEEDED;
+ if (zfcp_erp_adapter_strategy_open_fsf(act)) {
+ zfcp_erp_adapter_strategy_close(act);
+ return ZFCP_ERP_FAILED;
+ }
- close_only:
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
- &act->adapter->status);
+ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
- failed_openfcp:
- /* close queues to ensure that buffers are not accessed by adapter */
- zfcp_qdio_close(adapter);
- zfcp_fsf_req_dismiss_all(adapter);
- 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);
- failed_qdio:
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_ADAPTER_XPORT_OK,
- &act->adapter->status);
- return retval;
+ return ZFCP_ERP_SUCCEEDED;
}
static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
{
- int retval;
-
- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status);
- zfcp_erp_adapter_strategy_generic(act, 1); /* close */
- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status);
- if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
- return ZFCP_ERP_EXIT;
+ struct zfcp_adapter *adapter = act->adapter;
- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status);
- retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status);
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
+ zfcp_erp_adapter_strategy_close(act);
+ if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
+ return ZFCP_ERP_EXIT;
+ }
- if (retval == ZFCP_ERP_FAILED)
+ if (zfcp_erp_adapter_strategy_open(act)) {
ssleep(8);
+ return ZFCP_ERP_FAILED;
+ }
- return retval;
+ return ZFCP_ERP_SUCCEEDED;
}
static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
@@ -783,13 +823,7 @@ static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
{
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING |
- ZFCP_STATUS_COMMON_CLOSING |
- ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_PORT_DID_DID |
- ZFCP_STATUS_PORT_PHYS_CLOSING |
- ZFCP_STATUS_PORT_INVALID_WWPN,
- &port->status);
+ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
}
static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
@@ -807,7 +841,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;
@@ -839,78 +873,16 @@ static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_CONTINUES;
}
-static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act)
-{
- unsigned long flags;
- struct zfcp_adapter *adapter = ns_act->adapter;
- struct zfcp_erp_action *act, *tmp;
- int status;
-
- read_lock_irqsave(&adapter->erp_lock, flags);
- list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) {
- if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) {
- status = atomic_read(&adapter->nameserver_port->status);
- if (status & ZFCP_STATUS_COMMON_ERP_FAILED)
- zfcp_erp_port_failed(act->port, 27, NULL);
- zfcp_erp_action_ready(act);
- }
- }
- read_unlock_irqrestore(&adapter->erp_lock, flags);
-}
-
-static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act)
-{
- int retval;
-
- switch (act->step) {
- case ZFCP_ERP_STEP_UNINITIALIZED:
- case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
- case ZFCP_ERP_STEP_PORT_CLOSING:
- return zfcp_erp_port_strategy_open_port(act);
-
- case ZFCP_ERP_STEP_PORT_OPENING:
- if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN)
- retval = ZFCP_ERP_SUCCEEDED;
- else
- retval = ZFCP_ERP_FAILED;
- /* this is needed anyway */
- zfcp_erp_port_strategy_open_ns_wake(act);
- return retval;
-
- default:
- return ZFCP_ERP_FAILED;
- }
-}
-
-static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act)
-{
- int retval;
-
- retval = zfcp_fc_ns_gid_pn_request(act);
- if (retval == -ENOMEM)
- return ZFCP_ERP_NOMEM;
- act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
- if (retval)
- return ZFCP_ERP_FAILED;
- return ZFCP_ERP_CONTINUES;
-}
-
static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
{
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
if (port->wwpn != adapter->peer_wwpn) {
- dev_err(&adapter->ccw_device->dev,
- "Failed to open port 0x%016Lx, "
- "Peer WWPN 0x%016Lx does not "
- "match.\n", port->wwpn,
- adapter->peer_wwpn);
- zfcp_erp_port_failed(port, 25, NULL);
+ zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
return ZFCP_ERP_FAILED;
}
port->d_id = adapter->peer_d_id;
- atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
return zfcp_erp_port_strategy_open_port(act);
}
@@ -918,7 +890,6 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
{
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
- struct zfcp_port *ns_port = adapter->nameserver_port;
int p_status = atomic_read(&port->status);
switch (act->step) {
@@ -927,151 +898,139 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
case ZFCP_ERP_STEP_PORT_CLOSING:
if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
return zfcp_erp_open_ptp_port(act);
- if (!ns_port) {
- dev_err(&adapter->ccw_device->dev,
- "Nameserver port unavailable.\n");
- return ZFCP_ERP_FAILED;
- }
- if (!(atomic_read(&ns_port->status) &
- ZFCP_STATUS_COMMON_UNBLOCKED)) {
- /* nameserver port may live again */
- atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING,
- &ns_port->status);
- if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) {
- act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN;
- return ZFCP_ERP_CONTINUES;
- }
- return ZFCP_ERP_FAILED;
- }
- /* else nameserver port is already open, fall through */
- case ZFCP_ERP_STEP_NAMESERVER_OPEN:
- if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN))
- return ZFCP_ERP_FAILED;
- return zfcp_erp_port_strategy_open_lookup(act);
-
- case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
- if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) {
- if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) {
- zfcp_erp_port_failed(port, 26, NULL);
- return ZFCP_ERP_EXIT;
- }
- return ZFCP_ERP_FAILED;
+ if (!port->d_id) {
+ zfcp_fc_trigger_did_lookup(port);
+ return ZFCP_ERP_EXIT;
}
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) &&
- (p_status & ZFCP_STATUS_PORT_DID_DID))
+ if (p_status & ZFCP_STATUS_COMMON_OPEN) {
+ if (!port->d_id) {
+ zfcp_fc_trigger_did_lookup(port);
+ return ZFCP_ERP_EXIT;
+ }
return ZFCP_ERP_SUCCEEDED;
+ }
+ if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
+ port->d_id = 0;
+ return ZFCP_ERP_FAILED;
+ }
/* fall through otherwise */
}
return ZFCP_ERP_FAILED;
}
-static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act)
-{
- if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA))
- return zfcp_erp_port_strategy_open_nameserver(act);
- return zfcp_erp_port_strategy_open_common(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 ((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;
}
+
+close_init_done:
if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
return ZFCP_ERP_EXIT;
- else
- return zfcp_erp_port_strategy_open(erp_action);
- return ZFCP_ERP_FAILED;
+ return zfcp_erp_port_strategy_open_common(erp_action);
}
-static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
+static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
{
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING |
- ZFCP_STATUS_COMMON_CLOSING |
- ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_UNIT_SHARED |
- ZFCP_STATUS_UNIT_READONLY,
- &unit->status);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
+ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED,
+ &zfcp_sdev->status);
}
-static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
+static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action)
{
- int retval = zfcp_fsf_close_unit(erp_action);
+ int retval = zfcp_fsf_close_lun(erp_action);
if (retval == -ENOMEM)
return ZFCP_ERP_NOMEM;
- erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
+ erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
if (retval)
return ZFCP_ERP_FAILED;
return ZFCP_ERP_CONTINUES;
}
-static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
+static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action)
{
- int retval = zfcp_fsf_open_unit(erp_action);
+ int retval = zfcp_fsf_open_lun(erp_action);
if (retval == -ENOMEM)
return ZFCP_ERP_NOMEM;
- erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
+ erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
if (retval)
return ZFCP_ERP_FAILED;
return ZFCP_ERP_CONTINUES;
}
-static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
+static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action)
{
- struct zfcp_unit *unit = erp_action->unit;
+ struct scsi_device *sdev = erp_action->sdev;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
switch (erp_action->step) {
case ZFCP_ERP_STEP_UNINITIALIZED:
- zfcp_erp_unit_strategy_clearstati(unit);
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
- return zfcp_erp_unit_strategy_close(erp_action);
+ zfcp_erp_lun_strategy_clearstati(sdev);
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
+ return zfcp_erp_lun_strategy_close(erp_action);
/* already closed, fall through */
- case ZFCP_ERP_STEP_UNIT_CLOSING:
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
+ case ZFCP_ERP_STEP_LUN_CLOSING:
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
return ZFCP_ERP_FAILED;
if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
return ZFCP_ERP_EXIT;
- return zfcp_erp_unit_strategy_open(erp_action);
+ return zfcp_erp_lun_strategy_open(erp_action);
- case ZFCP_ERP_STEP_UNIT_OPENING:
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
+ case ZFCP_ERP_STEP_LUN_OPENING:
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
return ZFCP_ERP_SUCCEEDED;
}
return ZFCP_ERP_FAILED;
}
-static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
+static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result)
{
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
switch (result) {
case ZFCP_ERP_SUCCEEDED :
- atomic_set(&unit->erp_counter, 0);
- zfcp_erp_unit_unblock(unit);
+ atomic_set(&zfcp_sdev->erp_counter, 0);
+ zfcp_erp_lun_unblock(sdev);
break;
case ZFCP_ERP_FAILED :
- atomic_inc(&unit->erp_counter);
- if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS)
- zfcp_erp_unit_failed(unit, 21, NULL);
+ atomic_inc(&zfcp_sdev->erp_counter);
+ if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
+ "ERP failed for LUN 0x%016Lx on "
+ "port 0x%016Lx\n",
+ (unsigned long long)zfcp_scsi_dev_lun(sdev),
+ (unsigned long long)zfcp_sdev->port->wwpn);
+ zfcp_erp_set_lun_status(sdev,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
+ }
break;
}
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
- zfcp_erp_unit_block(unit, 0);
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
+ zfcp_erp_lun_block(sdev, 0);
result = ZFCP_ERP_EXIT;
}
return result;
@@ -1091,8 +1050,13 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
result = ZFCP_ERP_EXIT;
}
atomic_inc(&port->erp_counter);
- if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
- zfcp_erp_port_failed(port, 22, NULL);
+ if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&port->adapter->ccw_device->dev,
+ "ERP failed for remote port 0x%016Lx\n",
+ (unsigned long long)port->wwpn);
+ zfcp_erp_set_port_status(port,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
+ }
break;
}
@@ -1114,8 +1078,13 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
case ZFCP_ERP_FAILED :
atomic_inc(&adapter->erp_counter);
- if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS)
- zfcp_erp_adapter_failed(adapter, 23, NULL);
+ if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&adapter->ccw_device->dev,
+ "ERP cannot recover an error "
+ "on the FCP device\n");
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
+ }
break;
}
@@ -1131,12 +1100,12 @@ static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- struct zfcp_unit *unit = erp_action->unit;
+ struct scsi_device *sdev = erp_action->sdev;
switch (erp_action->action) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- result = zfcp_erp_strategy_check_unit(unit, result);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ result = zfcp_erp_strategy_check_lun(sdev, result);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
@@ -1171,7 +1140,8 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
int action = act->action;
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
- struct zfcp_unit *unit = act->unit;
+ struct scsi_device *sdev = act->sdev;
+ struct zfcp_scsi_dev *zfcp_sdev;
u32 erp_status = act->status;
switch (action) {
@@ -1179,7 +1149,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
_zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_COMMON_ERP_FAILED,
- 67, NULL);
+ "ersscg1");
return ZFCP_ERP_EXIT;
}
break;
@@ -1189,16 +1159,17 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
_zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- 68, NULL);
+ "ersscg2");
return ZFCP_ERP_EXIT;
}
break;
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
- _zfcp_erp_unit_reopen(unit,
- ZFCP_STATUS_COMMON_ERP_FAILED,
- 69, NULL);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
+ _zfcp_erp_lun_reopen(sdev,
+ ZFCP_STATUS_COMMON_ERP_FAILED,
+ "ersscg3", 0);
return ZFCP_ERP_EXIT;
}
break;
@@ -1209,6 +1180,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_scsi_dev *zfcp_sdev;
adapter->erp_total_count--;
if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
@@ -1217,12 +1189,13 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
}
list_del(&erp_action->list);
- zfcp_rec_dbf_event_action(144, erp_action);
+ zfcp_dbf_rec_run("eractd1", erp_action);
switch (erp_action->action) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
- &erp_action->unit->status);
+ &zfcp_sdev->status);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
@@ -1238,113 +1211,35 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
}
}
-struct zfcp_erp_add_work {
- struct zfcp_unit *unit;
- struct work_struct work;
-};
-
-static void zfcp_erp_scsi_scan(struct work_struct *work)
-{
- struct zfcp_erp_add_work *p =
- container_of(work, struct zfcp_erp_add_work, work);
- struct zfcp_unit *unit = p->unit;
- struct fc_rport *rport = unit->port->rport;
- scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
- unit->scsi_lun, 0);
- atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
- zfcp_unit_put(unit);
- kfree(p);
-}
-
-static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
-{
- struct zfcp_erp_add_work *p;
-
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p) {
- dev_err(&unit->port->adapter->ccw_device->dev,
- "Out of resources. Could not register unit "
- "0x%016Lx on port 0x%016Lx with SCSI stack.\n",
- unit->fcp_lun, unit->port->wwpn);
- return;
- }
-
- zfcp_unit_get(unit);
- atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
- INIT_WORK(&p->work, zfcp_erp_scsi_scan);
- p->unit = unit;
- schedule_work(&p->work);
-}
-
-static void zfcp_erp_rport_register(struct zfcp_port *port)
-{
- struct fc_rport_identifiers ids;
- ids.node_name = port->wwnn;
- ids.port_name = port->wwpn;
- ids.port_id = port->d_id;
- ids.roles = FC_RPORT_ROLE_FCP_TARGET;
- port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
- if (!port->rport) {
- dev_err(&port->adapter->ccw_device->dev,
- "Failed registration of rport "
- "0x%016Lx.\n", port->wwpn);
- return;
- }
-
- scsi_target_unblock(&port->rport->dev);
- port->rport->maxframe_size = port->maxframe_size;
- port->rport->supported_classes = port->supported_classes;
-}
-
-static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
-{
- struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port->rport && !(atomic_read(&port->status) &
- ZFCP_STATUS_PORT_WKA)) {
- fc_remote_port_delete(port->rport);
- port->rport = NULL;
- }
-}
-
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
{
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
- struct zfcp_unit *unit = act->unit;
+ struct scsi_device *sdev = act->sdev;
switch (act->action) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if ((result == ZFCP_ERP_SUCCEEDED) &&
- !unit->device && port->rport) {
- atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
- &unit->status);
- if (!(atomic_read(&unit->status) &
- ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
- zfcp_erp_schedule_work(unit);
- }
- zfcp_unit_put(unit);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
+ scsi_device_put(sdev);
break;
- case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) {
- zfcp_port_put(port);
- return;
- }
- if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport)
- zfcp_erp_rport_register(port);
- if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
- fc_remote_port_delete(port->rport);
- port->rport = NULL;
- }
- zfcp_port_put(port);
+ if (result == ZFCP_ERP_SUCCEEDED)
+ zfcp_scsi_schedule_rport_register(port);
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+ put_device(&port->dev);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- if (result != ZFCP_ERP_SUCCEEDED)
- zfcp_erp_rports_del(adapter);
- zfcp_adapter_put(adapter);
+ if (result == ZFCP_ERP_SUCCEEDED) {
+ register_service_level(&adapter->service_level);
+ zfcp_fc_conditional_port_scan(adapter);
+ queue_work(adapter->work_queue, &adapter->ns_up_work);
+ } else
+ unregister_service_level(&adapter->service_level);
+
+ kref_put(&adapter->ref, zfcp_adapter_release);
break;
}
}
@@ -1358,8 +1253,8 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
return zfcp_erp_port_forced_strategy(erp_action);
case ZFCP_ERP_ACTION_REOPEN_PORT:
return zfcp_erp_port_strategy(erp_action);
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- return zfcp_erp_unit_strategy(erp_action);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ return zfcp_erp_lun_strategy(erp_action);
}
return ZFCP_ERP_FAILED;
}
@@ -1367,12 +1262,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) {
@@ -1381,14 +1276,17 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
+ if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+ retval = ZFCP_ERP_FAILED;
+ goto check_target;
+ }
+
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;
@@ -1400,7 +1298,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
}
if (adapter->erp_total_count == adapter->erp_low_mem_count)
- _zfcp_erp_adapter_reopen(adapter, 0, 66, NULL);
+ _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1");
else {
zfcp_erp_strategy_memwait(erp_action);
retval = ZFCP_ERP_CONTINUES;
@@ -1415,20 +1313,24 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
+check_target:
retval = zfcp_erp_strategy_check_target(erp_action, retval);
zfcp_erp_action_dequeue(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;
}
@@ -1439,14 +1341,14 @@ static int zfcp_erp_thread(void *data)
struct zfcp_erp_action *act;
unsigned long flags;
- daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id);
- /* 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 (;;) {
+ wait_event_interruptible(adapter->erp_ready_wq,
+ !list_empty(&adapter->erp_ready_head) ||
+ kthread_should_stop());
+
+ 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);
@@ -1458,15 +1360,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(4, adapter);
- down_interruptible(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread(5, adapter);
}
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
- wake_up(&adapter->erp_thread_wqh);
-
return 0;
}
@@ -1478,18 +1373,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,
- "Creation of ERP thread failed.\n");
- return retval;
+ "Creating an ERP thread for the FCP device failed.\n");
+ 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;
}
@@ -1504,66 +1398,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(2, 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);
-}
-
-/**
- * zfcp_erp_adapter_failed - Set adapter status to failed.
- * @adapter: Failed adapter.
- * @id: Event id for debug trace.
- * @ref: Reference for debug trace.
- */
-void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref)
-{
- zfcp_erp_modify_adapter_status(adapter, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
- dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n");
-}
-
-/**
- * zfcp_erp_port_failed - Set port status to failed.
- * @port: Failed port.
- * @id: Event id for debug trace.
- * @ref: Reference for debug trace.
- */
-void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref)
-{
- zfcp_erp_modify_port_status(port, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-
- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)
- dev_err(&port->adapter->ccw_device->dev,
- "Port ERP failed for WKA port d_id=0x%06x.\n",
- port->d_id);
- else
- dev_err(&port->adapter->ccw_device->dev,
- "Port ERP failed for port wwpn=0x%016Lx.\n",
- port->wwpn);
-}
-
-/**
- * zfcp_erp_unit_failed - Set unit status to failed.
- * @unit: Failed unit.
- * @id: Event id for debug trace.
- * @ref: Reference for debug trace.
- */
-void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref)
-{
- zfcp_erp_modify_unit_status(unit, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-
- dev_err(&unit->port->adapter->ccw_device->dev,
- "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n",
- unit->fcp_lun, unit->port->wwpn);
+ 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));
}
/**
@@ -1578,211 +1416,158 @@ void zfcp_erp_wait(struct zfcp_adapter *adapter)
}
/**
- * zfcp_erp_modify_adapter_status - change adapter status bits
+ * zfcp_erp_set_adapter_status - set adapter status bits
* @adapter: adapter to change the status
- * @id: id for the debug trace
- * @ref: reference for the debug trace
* @mask: status bits to change
- * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
*
- * Changes in common status bits are propagated to attached ports and units.
+ * Changes in common status bits are propagated to attached ports and LUNs.
*/
-void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id,
- void *ref, u32 mask, int set_or_clear)
+void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
{
struct zfcp_port *port;
+ struct scsi_device *sdev;
+ 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);
- atomic_set_mask(mask, &adapter->status);
- } else {
- if (status_change_clear(mask, &adapter->status))
- zfcp_rec_dbf_event_adapter(id, ref, adapter);
- atomic_clear_mask(mask, &adapter->status);
- if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
- atomic_set(&adapter->erp_counter, 0);
- }
+ atomic_set_mask(mask, &adapter->status);
+
+ if (!common_mask)
+ return;
- if (common_mask)
- list_for_each_entry(port, &adapter->port_list_head, list)
- zfcp_erp_modify_port_status(port, id, ref, common_mask,
- set_or_clear);
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
+ atomic_set_mask(common_mask, &port->status);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
+
+ spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, adapter->scsi_host)
+ atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status);
+ spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
}
/**
- * zfcp_erp_modify_port_status - change port status bits
- * @port: port to change the status bits
- * @id: id for the debug trace
- * @ref: reference for the debug trace
+ * zfcp_erp_clear_adapter_status - clear adapter status bits
+ * @adapter: adapter to change the status
* @mask: status bits to change
- * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
*
- * Changes in common status bits are propagated to attached units.
+ * Changes in common status bits are propagated to attached ports and LUNs.
*/
-void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref,
- u32 mask, int set_or_clear)
+void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
{
- struct zfcp_unit *unit;
+ struct zfcp_port *port;
+ struct scsi_device *sdev;
+ unsigned long flags;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+ u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
+
+ atomic_clear_mask(mask, &adapter->status);
+
+ if (!common_mask)
+ return;
- if (set_or_clear == ZFCP_SET) {
- if (status_change_set(mask, &port->status))
- zfcp_rec_dbf_event_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);
- atomic_clear_mask(mask, &port->status);
- if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
+ if (clear_counter)
+ atomic_set(&adapter->erp_counter, 0);
+
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list) {
+ atomic_clear_mask(common_mask, &port->status);
+ if (clear_counter)
atomic_set(&port->erp_counter, 0);
}
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
- if (common_mask)
- list_for_each_entry(unit, &port->unit_list_head, list)
- zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
- set_or_clear);
-}
-
-/**
- * zfcp_erp_modify_unit_status - change unit status bits
- * @unit: unit to change the status bits
- * @id: id for the debug trace
- * @ref: reference for the debug trace
- * @mask: status bits to change
- * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
- */
-void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref,
- u32 mask, int set_or_clear)
-{
- if (set_or_clear == ZFCP_SET) {
- if (status_change_set(mask, &unit->status))
- zfcp_rec_dbf_event_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);
- atomic_clear_mask(mask, &unit->status);
- if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
- atomic_set(&unit->erp_counter, 0);
- }
+ spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, adapter->scsi_host) {
+ atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);
+ if (clear_counter)
+ atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
}
+ spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
}
/**
- * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
- * @port: The "boxed" port.
- * @id: The debug trace id.
- * @id: Reference for the debug trace.
+ * zfcp_erp_set_port_status - set port status bits
+ * @port: port to change the status
+ * @mask: status bits to change
+ *
+ * Changes in common status bits are propagated to attached LUNs.
*/
-void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref)
+void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
{
+ struct scsi_device *sdev;
+ u32 common_mask = mask & ZFCP_COMMON_FLAGS;
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);
-}
+ atomic_set_mask(mask, &port->status);
-/**
- * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
- * @port: The "boxed" unit.
- * @id: The debug trace id.
- * @id: Reference for the debug trace.
- */
-void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref)
-{
- zfcp_erp_modify_unit_status(unit, id, ref,
- ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
- zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
+ if (!common_mask)
+ return;
+
+ spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
+ if (sdev_to_zfcp(sdev)->port == port)
+ atomic_set_mask(common_mask,
+ &sdev_to_zfcp(sdev)->status);
+ spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
}
/**
- * zfcp_erp_port_access_denied - Adapter denied access to port.
- * @port: port where access has been denied
- * @id: id for debug trace
- * @ref: reference for debug trace
+ * zfcp_erp_clear_port_status - clear port status bits
+ * @port: adapter to change the status
+ * @mask: status bits to change
*
- * Since the adapter has denied access, stop using the port and the
- * attached units.
+ * Changes in common status bits are propagated to attached LUNs.
*/
-void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref)
+void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
{
+ struct scsi_device *sdev;
+ u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+ u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
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);
-}
-
-/**
- * zfcp_erp_unit_access_denied - Adapter denied access to unit.
- * @unit: unit where access has been denied
- * @id: id for debug trace
- * @ref: reference for debug trace
- *
- * Since the adapter has denied access, stop using the unit.
- */
-void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref)
-{
- zfcp_erp_modify_unit_status(unit, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED |
- ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
-}
+ atomic_clear_mask(mask, &port->status);
-static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id,
- void *ref)
-{
- int status = atomic_read(&unit->status);
- if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_COMMON_ACCESS_BOXED)))
+ if (!common_mask)
return;
- zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
+ if (clear_counter)
+ atomic_set(&port->erp_counter, 0);
+
+ spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
+ if (sdev_to_zfcp(sdev)->port == port) {
+ atomic_clear_mask(common_mask,
+ &sdev_to_zfcp(sdev)->status);
+ if (clear_counter)
+ atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
+ }
+ spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
}
-static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id,
- void *ref)
+/**
+ * zfcp_erp_set_lun_status - set lun status bits
+ * @sdev: SCSI device / lun to set the status bits
+ * @mask: status bits to change
+ */
+void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask)
{
- struct zfcp_unit *unit;
- int status = atomic_read(&port->status);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
- if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
- if (!(status & ZFCP_STATUS_PORT_WKA))
- list_for_each_entry(unit, &port->unit_list_head, list)
- zfcp_erp_unit_access_changed(unit, id, ref);
- return;
- }
-
- zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
+ atomic_set_mask(mask, &zfcp_sdev->status);
}
/**
- * zfcp_erp_adapter_access_changed - Process change in adapter ACT
- * @adapter: Adapter where the Access Control Table (ACT) changed
- * @id: Id for debug trace
- * @ref: Reference for debug trace
+ * zfcp_erp_clear_lun_status - clear lun status bits
+ * @sdev: SCSi device / lun to clear the status bits
+ * @mask: status bits to change
*/
-void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id,
- void *ref)
+void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask)
{
- struct zfcp_port *port;
- unsigned long flags;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
- if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
- return;
+ atomic_clear_mask(mask, &zfcp_sdev->status);
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- if (adapter->nameserver_port)
- zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref);
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port != adapter->nameserver_port)
- zfcp_erp_port_access_changed(port, id, ref);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
+ atomic_set(&zfcp_sdev->erp_counter, 0);
}
+