aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/block/dasd.c22
-rw-r--r--drivers/s390/block/dasd_3990_erp.c20
-rw-r--r--drivers/s390/block/dasd_alias.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c70
-rw-r--r--drivers/s390/block/dasd_eckd.h2
-rw-r--r--drivers/s390/block/dasd_int.h5
6 files changed, 124 insertions, 3 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index fa2339cb1681..0e86247d791e 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -65,6 +65,7 @@ static void dasd_device_tasklet(struct dasd_device *);
65static void dasd_block_tasklet(struct dasd_block *); 65static void dasd_block_tasklet(struct dasd_block *);
66static void do_kick_device(struct work_struct *); 66static void do_kick_device(struct work_struct *);
67static void do_restore_device(struct work_struct *); 67static void do_restore_device(struct work_struct *);
68static void do_reload_device(struct work_struct *);
68static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); 69static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
69static void dasd_device_timeout(unsigned long); 70static void dasd_device_timeout(unsigned long);
70static void dasd_block_timeout(unsigned long); 71static void dasd_block_timeout(unsigned long);
@@ -115,6 +116,7 @@ struct dasd_device *dasd_alloc_device(void)
115 device->timer.data = (unsigned long) device; 116 device->timer.data = (unsigned long) device;
116 INIT_WORK(&device->kick_work, do_kick_device); 117 INIT_WORK(&device->kick_work, do_kick_device);
117 INIT_WORK(&device->restore_device, do_restore_device); 118 INIT_WORK(&device->restore_device, do_restore_device);
119 INIT_WORK(&device->reload_device, do_reload_device);
118 device->state = DASD_STATE_NEW; 120 device->state = DASD_STATE_NEW;
119 device->target = DASD_STATE_NEW; 121 device->target = DASD_STATE_NEW;
120 mutex_init(&device->state_mutex); 122 mutex_init(&device->state_mutex);
@@ -521,6 +523,26 @@ void dasd_kick_device(struct dasd_device *device)
521} 523}
522 524
523/* 525/*
526 * dasd_reload_device will schedule a call do do_reload_device to the kernel
527 * event daemon.
528 */
529static void do_reload_device(struct work_struct *work)
530{
531 struct dasd_device *device = container_of(work, struct dasd_device,
532 reload_device);
533 device->discipline->reload(device);
534 dasd_put_device(device);
535}
536
537void dasd_reload_device(struct dasd_device *device)
538{
539 dasd_get_device(device);
540 /* queue call to dasd_reload_device to the kernel event daemon. */
541 schedule_work(&device->reload_device);
542}
543EXPORT_SYMBOL(dasd_reload_device);
544
545/*
524 * dasd_restore_device will schedule a call do do_restore_device to the kernel 546 * dasd_restore_device will schedule a call do do_restore_device to the kernel
525 * event daemon. 547 * event daemon.
526 */ 548 */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 6632649dd6aa..85bfd8794856 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1418,9 +1418,29 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
1418 struct dasd_ccw_req *erp) 1418 struct dasd_ccw_req *erp)
1419{ 1419{
1420 struct dasd_ccw_req *cqr = erp->refers; 1420 struct dasd_ccw_req *cqr = erp->refers;
1421 char *sense;
1421 1422
1422 if (cqr->block && 1423 if (cqr->block &&
1423 (cqr->block->base != cqr->startdev)) { 1424 (cqr->block->base != cqr->startdev)) {
1425
1426 sense = dasd_get_sense(&erp->refers->irb);
1427 /*
1428 * dynamic pav may have changed base alias mapping
1429 */
1430 if (!test_bit(DASD_FLAG_OFFLINE, &cqr->startdev->flags) && sense
1431 && (sense[0] == 0x10) && (sense[7] == 0x0F)
1432 && (sense[8] == 0x67)) {
1433 /*
1434 * remove device from alias handling to prevent new
1435 * requests from being scheduled on the
1436 * wrong alias device
1437 */
1438 dasd_alias_remove_device(cqr->startdev);
1439
1440 /* schedule worker to reload device */
1441 dasd_reload_device(cqr->startdev);
1442 }
1443
1424 if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { 1444 if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
1425 DBF_DEV_EVENT(DBF_ERR, cqr->startdev, 1445 DBF_DEV_EVENT(DBF_ERR, cqr->startdev,
1426 "ERP on alias device for request %p," 1446 "ERP on alias device for request %p,"
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 8c4814258e93..a564b9941114 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -642,6 +642,14 @@ int dasd_alias_add_device(struct dasd_device *device)
642 return rc; 642 return rc;
643} 643}
644 644
645int dasd_alias_update_add_device(struct dasd_device *device)
646{
647 struct dasd_eckd_private *private;
648 private = (struct dasd_eckd_private *) device->private;
649 private->lcu->flags |= UPDATE_PENDING;
650 return dasd_alias_add_device(device);
651}
652
645int dasd_alias_remove_device(struct dasd_device *device) 653int dasd_alias_remove_device(struct dasd_device *device)
646{ 654{
647 struct dasd_eckd_private *private; 655 struct dasd_eckd_private *private;
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
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 864d53c04201..dd6385a5af14 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -426,7 +426,6 @@ struct alias_pav_group {
426 struct dasd_device *next; 426 struct dasd_device *next;
427}; 427};
428 428
429
430struct dasd_eckd_private { 429struct dasd_eckd_private {
431 struct dasd_eckd_characteristics rdc_data; 430 struct dasd_eckd_characteristics rdc_data;
432 u8 *conf_data; 431 u8 *conf_data;
@@ -463,4 +462,5 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
463void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); 462void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
464void dasd_alias_lcu_setup_complete(struct dasd_device *); 463void dasd_alias_lcu_setup_complete(struct dasd_device *);
465void dasd_alias_wait_for_lcu_setup(struct dasd_device *); 464void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
465int dasd_alias_update_add_device(struct dasd_device *);
466#endif /* DASD_ECKD_H */ 466#endif /* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a91d4a97d4f2..1ae7b121628e 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -312,6 +312,9 @@ struct dasd_discipline {
312 /* suspend/resume functions */ 312 /* suspend/resume functions */
313 int (*freeze) (struct dasd_device *); 313 int (*freeze) (struct dasd_device *);
314 int (*restore) (struct dasd_device *); 314 int (*restore) (struct dasd_device *);
315
316 /* reload device after state change */
317 int (*reload) (struct dasd_device *);
315}; 318};
316 319
317extern struct dasd_discipline *dasd_diag_discipline_pointer; 320extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -386,6 +389,7 @@ struct dasd_device {
386 struct tasklet_struct tasklet; 389 struct tasklet_struct tasklet;
387 struct work_struct kick_work; 390 struct work_struct kick_work;
388 struct work_struct restore_device; 391 struct work_struct restore_device;
392 struct work_struct reload_device;
389 struct timer_list timer; 393 struct timer_list timer;
390 394
391 debug_info_t *debug_area; 395 debug_info_t *debug_area;
@@ -582,6 +586,7 @@ void dasd_enable_device(struct dasd_device *);
582void dasd_set_target_state(struct dasd_device *, int); 586void dasd_set_target_state(struct dasd_device *, int);
583void dasd_kick_device(struct dasd_device *); 587void dasd_kick_device(struct dasd_device *);
584void dasd_restore_device(struct dasd_device *); 588void dasd_restore_device(struct dasd_device *);
589void dasd_reload_device(struct dasd_device *);
585 590
586void dasd_add_request_head(struct dasd_ccw_req *); 591void dasd_add_request_head(struct dasd_ccw_req *);
587void dasd_add_request_tail(struct dasd_ccw_req *); 592void dasd_add_request_tail(struct dasd_ccw_req *);