diff options
author | Stefan Haberland <stefan.haberland@de.ibm.com> | 2010-05-17 12:00:10 +0400 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-05-17 12:00:16 +0400 |
commit | 501183f2ed74434e30a1b039b2f3af30f1f3f461 (patch) | |
tree | 785b6f2b2d5c7858e557354f71bdb0928fa098b1 /drivers/s390/block/dasd_eckd.c | |
parent | f3cb31e495668eae568c584c666631e26c68bdea (diff) | |
download | linux-501183f2ed74434e30a1b039b2f3af30f1f3f461.tar.xz |
[S390] dasd: add dynamic pav toleration
For base Parallel Access Volume (PAV) there is a fixed mapping of
base and alias devices. With dynamic PAV this mapping can be changed
so that an alias device is used with another base device.
This patch enables the DASD device driver to tolerate dynamic PAV
changes.
Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 0cb233116855..4305c23c57a4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1451,6 +1451,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); return dasd_alias_remove_device(device); }; @@ -1709,10 +1710,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, { char mask; char *sense = NULL; + struct dasd_eckd_private *private; + private = (struct dasd_eckd_private *) device->private; /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; if ((scsw_dstat(&irb->scsw) & mask) == mask) { + /* for alias only and not in offline processing*/ + if (!device->block && private->lcu && + !test_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* + * the state change could be caused by an alias + * reassignment remove device from alias handling + * to prevent new requests from being scheduled on + * the wrong alias device + */ + dasd_alias_remove_device(device); + + /* schedule worker to reload device */ + dasd_reload_device(device); + } + dasd_generic_handle_state_change(device); return; } @@ -3259,7 +3277,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, dasd_eckd_dump_sense_ccw(device, req, irb); } -int dasd_eckd_pm_freeze(struct dasd_device *device) +static int dasd_eckd_pm_freeze(struct dasd_device *device) { /* * the device should be disconnected from our LCU structure @@ -3272,7 +3290,7 @@ int dasd_eckd_pm_freeze(struct dasd_device *device) return 0; } -int dasd_eckd_restore_device(struct dasd_device *device) +static int dasd_eckd_restore_device(struct dasd_device *device) { struct dasd_eckd_private *private; struct dasd_eckd_characteristics temp_rdc_data; @@ -3336,6 +3354,53 @@ out_err: return -1; } +static int dasd_eckd_reload_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + int rc, old_base; + char uid[60]; + + private = (struct dasd_eckd_private *) device->private; + old_base = private->uid.base_unit_addr; + /* Read Configuration Data */ + rc = dasd_eckd_read_conf(device); + if (rc) + goto out_err; + + rc = dasd_eckd_generate_uid(device, &private->uid); + if (rc) + goto out_err; + + dasd_set_uid(device->cdev, &private->uid); + + /* + * update unit address configuration and + * add device to alias management + */ + dasd_alias_update_add_device(device); + + if (old_base != private->uid.base_unit_addr) { + if (strlen(private->uid.vduit) > 0) + snprintf(uid, 60, "%s.%s.%04x.%02x.%s", + private->uid.vendor, private->uid.serial, + private->uid.ssid, private->uid.base_unit_addr, + private->uid.vduit); + else + snprintf(uid, 60, "%s.%s.%04x.%02x", + private->uid.vendor, private->uid.serial, + private->uid.ssid, + private->uid.base_unit_addr); + + dev_info(&device->cdev->dev, + "An Alias device was reassigned to a new base device " + "with UID: %s\n", uid); + } + return 0; + +out_err: + return -1; +} + static struct ccw_driver dasd_eckd_driver = { .name = "dasd-eckd", .owner = THIS_MODULE, @@ -3389,6 +3454,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .ioctl = dasd_eckd_ioctl, .freeze = dasd_eckd_pm_freeze, .restore = dasd_eckd_restore_device, + .reload = dasd_eckd_reload_device, }; static int __init |