aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r--drivers/s390/block/dasd_eckd.c73
1 files changed, 46 insertions, 27 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index bbcd5e9206ee..c21871a4e73d 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -18,12 +18,12 @@
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h>
#include <linux/module.h>
+#include <linux/compat.h>
#include <linux/init.h>
#include <asm/debug.h>
#include <asm/idals.h>
#include <asm/ebcdic.h>
-#include <asm/compat.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/cio.h>
@@ -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,34 @@ 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);
+ /* exit if device not online or in offline processing */
+ if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
+ device->state < DASD_STATE_ONLINE) {
+ dasd_put_device(device);
+ return;
+ }
+ /* 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 +1615,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 +1681,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);
@@ -1979,6 +1999,7 @@ static int dasd_eckd_ready_to_online(struct dasd_device *device)
static int dasd_eckd_online_to_ready(struct dasd_device *device)
{
cancel_work_sync(&device->reload_device);
+ cancel_work_sync(&device->kick_validate);
return dasd_alias_remove_device(device);
};
@@ -2249,6 +2270,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
* and only if not suspended
*/
if (!device->block && private->lcu &&
+ device->state == DASD_STATE_ONLINE &&
!test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
!test_bit(DASD_FLAG_SUSPENDED, &device->flags)) {
/*
@@ -4098,7 +4120,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 +4143,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 +4288,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