summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-02-04 16:39:32 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-04 16:39:32 -0500
commitdd48dc34fe7639a8b2e22d8b609672f5f81aa7cb (patch)
treef16ace0ae09edab16bf6d0be9e8280dfbb7100da /drivers/s390
parent8d9eb069eafce49307f839783e4a4673414b1fd5 (diff)
parent5962b35c1de3254a2f03b95efd3b7854b874d7b7 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c6
-rw-r--r--drivers/s390/block/dasd_alias.c64
-rw-r--r--drivers/s390/block/dasd_eckd.c63
-rw-r--r--drivers/s390/block/dasd_int.h2
4 files changed, 46 insertions, 89 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index eef27a197c0..110137e7ec8 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3261,6 +3261,12 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
device->path_data.tbvpm |= eventlpm;
dasd_schedule_device_bh(device);
}
+ if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) {
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+ "Pathgroup re-established\n");
+ if (device->discipline->kick_validate)
+ device->discipline->kick_validate(device);
+ }
}
dasd_put_device(device);
}
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 553b3c5abb0..b3beed5434e 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -189,14 +189,12 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
unsigned long flags;
struct alias_server *server, *newserver;
struct alias_lcu *lcu, *newlcu;
- int is_lcu_known;
struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private;
device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&aliastree.lock, flags);
- is_lcu_known = 1;
server = _find_server(&uid);
if (!server) {
spin_unlock_irqrestore(&aliastree.lock, flags);
@@ -208,7 +206,6 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
if (!server) {
list_add(&newserver->server, &aliastree.serverlist);
server = newserver;
- is_lcu_known = 0;
} else {
/* someone was faster */
_free_server(newserver);
@@ -226,12 +223,10 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
if (!lcu) {
list_add(&newlcu->lcu, &server->lculist);
lcu = newlcu;
- is_lcu_known = 0;
} else {
/* someone was faster */
_free_lcu(newlcu);
}
- is_lcu_known = 0;
}
spin_lock(&lcu->lock);
list_add(&device->alias_list, &lcu->inactive_devices);
@@ -239,64 +234,7 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
spin_unlock(&lcu->lock);
spin_unlock_irqrestore(&aliastree.lock, flags);
- return is_lcu_known;
-}
-
-/*
- * The first device to be registered on an LCU will have to do
- * some additional setup steps to configure that LCU on the
- * storage server. All further devices should wait with their
- * initialization until the first device is done.
- * To synchronize this work, the first device will call
- * dasd_alias_lcu_setup_complete when it is done, and all
- * other devices will wait for it with dasd_alias_wait_for_lcu_setup.
- */
-void dasd_alias_lcu_setup_complete(struct dasd_device *device)
-{
- unsigned long flags;
- struct alias_server *server;
- struct alias_lcu *lcu;
- struct dasd_uid uid;
-
- device->discipline->get_uid(device, &uid);
- lcu = NULL;
- spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(&uid);
- if (server)
- lcu = _find_lcu(server, &uid);
- spin_unlock_irqrestore(&aliastree.lock, flags);
- if (!lcu) {
- DBF_EVENT_DEVID(DBF_ERR, device->cdev,
- "could not find lcu for %04x %02x",
- uid.ssid, uid.real_unit_addr);
- WARN_ON(1);
- return;
- }
- complete_all(&lcu->lcu_setup);
-}
-
-void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
-{
- unsigned long flags;
- struct alias_server *server;
- struct alias_lcu *lcu;
- struct dasd_uid uid;
-
- device->discipline->get_uid(device, &uid);
- lcu = NULL;
- spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(&uid);
- if (server)
- lcu = _find_lcu(server, &uid);
- spin_unlock_irqrestore(&aliastree.lock, flags);
- if (!lcu) {
- DBF_EVENT_DEVID(DBF_ERR, device->cdev,
- "could not find lcu for %04x %02x",
- uid.ssid, uid.real_unit_addr);
- WARN_ON(1);
- return;
- }
- wait_for_completion(&lcu->lcu_setup);
+ return 0;
}
/*
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index bbcd5e9206e..70880be2601 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1534,6 +1534,10 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
struct dasd_eckd_private *private;
int enable_pav;
+ private = (struct dasd_eckd_private *) device->private;
+ if (private->uid.type == UA_BASE_PAV_ALIAS ||
+ private->uid.type == UA_HYPER_PAV_ALIAS)
+ return;
if (dasd_nopav || MACHINE_IS_VM)
enable_pav = 0;
else
@@ -1542,11 +1546,28 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
/* may be requested feature is not available on server,
* therefore just report error and go ahead */
- private = (struct dasd_eckd_private *) device->private;
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
"returned rc=%d", private->uid.ssid, rc);
}
+/*
+ * worker to do a validate server in case of a lost pathgroup
+ */
+static void dasd_eckd_do_validate_server(struct work_struct *work)
+{
+ struct dasd_device *device = container_of(work, struct dasd_device,
+ kick_validate);
+ dasd_eckd_validate_server(device);
+ dasd_put_device(device);
+}
+
+static void dasd_eckd_kick_validate_server(struct dasd_device *device)
+{
+ dasd_get_device(device);
+ /* queue call to do_validate_server to the kernel event daemon. */
+ schedule_work(&device->kick_validate);
+}
+
static u32 get_fcx_max_data(struct dasd_device *device)
{
#if defined(CONFIG_64BIT)
@@ -1588,10 +1609,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
struct dasd_eckd_private *private;
struct dasd_block *block;
struct dasd_uid temp_uid;
- int is_known, rc, i;
+ int rc, i;
int readonly;
unsigned long value;
+ /* setup work queue for validate server*/
+ INIT_WORK(&device->kick_validate, dasd_eckd_do_validate_server);
+
if (!ccw_device_is_pathgroup(device->cdev)) {
dev_warn(&device->cdev->dev,
"A channel path group could not be established\n");
@@ -1651,22 +1675,12 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
block->base = device;
}
- /* register lcu with alias handling, enable PAV if this is a new lcu */
- is_known = dasd_alias_make_device_known_to_lcu(device);
- if (is_known < 0) {
- rc = is_known;
+ /* register lcu with alias handling, enable PAV */
+ rc = dasd_alias_make_device_known_to_lcu(device);
+ if (rc)
goto out_err2;
- }
- /*
- * dasd_eckd_validate_server is done on the first device that
- * is found for an LCU. All later other devices have to wait
- * for it, so they will read the correct feature codes.
- */
- if (!is_known) {
- dasd_eckd_validate_server(device);
- dasd_alias_lcu_setup_complete(device);
- } else
- dasd_alias_wait_for_lcu_setup(device);
+
+ dasd_eckd_validate_server(device);
/* device may report different configuration data after LCU setup */
rc = dasd_eckd_read_conf(device);
@@ -4098,7 +4112,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
{
struct dasd_eckd_private *private;
struct dasd_eckd_characteristics temp_rdc_data;
- int is_known, rc;
+ int rc;
struct dasd_uid temp_uid;
unsigned long flags;
@@ -4121,14 +4135,10 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
goto out_err;
/* register lcu with alias handling, enable PAV if this is a new lcu */
- is_known = dasd_alias_make_device_known_to_lcu(device);
- if (is_known < 0)
- return is_known;
- if (!is_known) {
- dasd_eckd_validate_server(device);
- dasd_alias_lcu_setup_complete(device);
- } else
- dasd_alias_wait_for_lcu_setup(device);
+ rc = dasd_alias_make_device_known_to_lcu(device);
+ if (rc)
+ return rc;
+ dasd_eckd_validate_server(device);
/* RE-Read Configuration Data */
rc = dasd_eckd_read_conf(device);
@@ -4270,6 +4280,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.restore = dasd_eckd_restore_device,
.reload = dasd_eckd_reload_device,
.get_uid = dasd_eckd_get_uid,
+ .kick_validate = dasd_eckd_kick_validate_server,
};
static int __init
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index afe8c33422e..33a6743ddc5 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -355,6 +355,7 @@ struct dasd_discipline {
int (*reload) (struct dasd_device *);
int (*get_uid) (struct dasd_device *, struct dasd_uid *);
+ void (*kick_validate) (struct dasd_device *);
};
extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -455,6 +456,7 @@ struct dasd_device {
struct work_struct kick_work;
struct work_struct restore_device;
struct work_struct reload_device;
+ struct work_struct kick_validate;
struct timer_list timer;
debug_info_t *debug_area;