aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
authorStefan Haberland <stefan.haberland@de.ibm.com>2010-05-17 04:00:10 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-05-17 04:00:16 -0400
commit501183f2ed74434e30a1b039b2f3af30f1f3f461 (patch)
tree785b6f2b2d5c7858e557354f71bdb0928fa098b1 /drivers/s390/block/dasd_eckd.c
parentf3cb31e495668eae568c584c666631e26c68bdea (diff)
[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.c70
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)
1451 1451
1452static int dasd_eckd_online_to_ready(struct dasd_device *device) 1452static int dasd_eckd_online_to_ready(struct dasd_device *device)
1453{ 1453{
1454 cancel_work_sync(&device->reload_device);
1454 return dasd_alias_remove_device(device); 1455 return dasd_alias_remove_device(device);
1455}; 1456};
1456 1457
@@ -1709,10 +1710,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
1709{ 1710{
1710 char mask; 1711 char mask;
1711 char *sense = NULL; 1712 char *sense = NULL;
1713 struct dasd_eckd_private *private;
1712 1714
1715 private = (struct dasd_eckd_private *) device->private;
1713 /* first of all check for state change pending interrupt */ 1716 /* first of all check for state change pending interrupt */
1714 mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; 1717 mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
1715 if ((scsw_dstat(&irb->scsw) & mask) == mask) { 1718 if ((scsw_dstat(&irb->scsw) & mask) == mask) {
1719 /* for alias only and not in offline processing*/
1720 if (!device->block && private->lcu &&
1721 !test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
1722 /*
1723 * the state change could be caused by an alias
1724 * reassignment remove device from alias handling
1725 * to prevent new requests from being scheduled on
1726 * the wrong alias device
1727 */
1728 dasd_alias_remove_device(device);
1729
1730 /* schedule worker to reload device */
1731 dasd_reload_device(device);
1732 }
1733
1716 dasd_generic_handle_state_change(device); 1734 dasd_generic_handle_state_change(device);
1717 return; 1735 return;
1718 } 1736 }
@@ -3259,7 +3277,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
3259 dasd_eckd_dump_sense_ccw(device, req, irb); 3277 dasd_eckd_dump_sense_ccw(device, req, irb);
3260} 3278}
3261 3279
3262int dasd_eckd_pm_freeze(struct dasd_device *device) 3280static int dasd_eckd_pm_freeze(struct dasd_device *device)
3263{ 3281{
3264 /* 3282 /*
3265 * the device should be disconnected from our LCU structure 3283 * the device should be disconnected from our LCU structure
@@ -3272,7 +3290,7 @@ int dasd_eckd_pm_freeze(struct dasd_device *device)
3272 return 0; 3290 return 0;
3273} 3291}
3274 3292
3275int dasd_eckd_restore_device(struct dasd_device *device) 3293static int dasd_eckd_restore_device(struct dasd_device *device)
3276{ 3294{
3277 struct dasd_eckd_private *private; 3295 struct dasd_eckd_private *private;
3278 struct dasd_eckd_characteristics temp_rdc_data; 3296 struct dasd_eckd_characteristics temp_rdc_data;
@@ -3336,6 +3354,53 @@ out_err:
3336 return -1; 3354 return -1;
3337} 3355}
3338 3356
3357static int dasd_eckd_reload_device(struct dasd_device *device)
3358{
3359 struct dasd_eckd_private *private;
3360 int rc, old_base;
3361 char uid[60];
3362
3363 private = (struct dasd_eckd_private *) device->private;
3364 old_base = private->uid.base_unit_addr;
3365 /* Read Configuration Data */
3366 rc = dasd_eckd_read_conf(device);
3367 if (rc)
3368 goto out_err;
3369
3370 rc = dasd_eckd_generate_uid(device, &private->uid);
3371 if (rc)
3372 goto out_err;
3373
3374 dasd_set_uid(device->cdev, &private->uid);
3375
3376 /*
3377 * update unit address configuration and
3378 * add device to alias management
3379 */
3380 dasd_alias_update_add_device(device);
3381
3382 if (old_base != private->uid.base_unit_addr) {
3383 if (strlen(private->uid.vduit) > 0)
3384 snprintf(uid, 60, "%s.%s.%04x.%02x.%s",
3385 private->uid.vendor, private->uid.serial,
3386 private->uid.ssid, private->uid.base_unit_addr,
3387 private->uid.vduit);
3388 else
3389 snprintf(uid, 60, "%s.%s.%04x.%02x",
3390 private->uid.vendor, private->uid.serial,
3391 private->uid.ssid,
3392 private->uid.base_unit_addr);
3393
3394 dev_info(&device->cdev->dev,
3395 "An Alias device was reassigned to a new base device "
3396 "with UID: %s\n", uid);
3397 }
3398 return 0;
3399
3400out_err:
3401 return -1;
3402}
3403
3339static struct ccw_driver dasd_eckd_driver = { 3404static struct ccw_driver dasd_eckd_driver = {
3340 .name = "dasd-eckd", 3405 .name = "dasd-eckd",
3341 .owner = THIS_MODULE, 3406 .owner = THIS_MODULE,
@@ -3389,6 +3454,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
3389 .ioctl = dasd_eckd_ioctl, 3454 .ioctl = dasd_eckd_ioctl,
3390 .freeze = dasd_eckd_pm_freeze, 3455 .freeze = dasd_eckd_pm_freeze,
3391 .restore = dasd_eckd_restore_device, 3456 .restore = dasd_eckd_restore_device,
3457 .reload = dasd_eckd_reload_device,
3392}; 3458};
3393 3459
3394static int __init 3460static int __init