diff options
-rw-r--r-- | drivers/s390/block/dasd.c | 22 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 20 | ||||
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 8 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 70 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 5 |
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 *); | |||
65 | static void dasd_block_tasklet(struct dasd_block *); | 65 | static void dasd_block_tasklet(struct dasd_block *); |
66 | static void do_kick_device(struct work_struct *); | 66 | static void do_kick_device(struct work_struct *); |
67 | static void do_restore_device(struct work_struct *); | 67 | static void do_restore_device(struct work_struct *); |
68 | static void do_reload_device(struct work_struct *); | ||
68 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); | 69 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); |
69 | static void dasd_device_timeout(unsigned long); | 70 | static void dasd_device_timeout(unsigned long); |
70 | static void dasd_block_timeout(unsigned long); | 71 | static 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 | */ | ||
529 | static 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 | |||
537 | void 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 | } | ||
543 | EXPORT_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 | ||
645 | int 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 | |||
645 | int dasd_alias_remove_device(struct dasd_device *device) | 653 | int 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 | ||
1452 | static int dasd_eckd_online_to_ready(struct dasd_device *device) | 1452 | static 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 | ||
3262 | int dasd_eckd_pm_freeze(struct dasd_device *device) | 3280 | static 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 | ||
3275 | int dasd_eckd_restore_device(struct dasd_device *device) | 3293 | static 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 | ||
3357 | static 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 | |||
3400 | out_err: | ||
3401 | return -1; | ||
3402 | } | ||
3403 | |||
3339 | static struct ccw_driver dasd_eckd_driver = { | 3404 | static 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 | ||
3394 | static int __init | 3460 | static 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 | |||
430 | struct dasd_eckd_private { | 429 | struct 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 *); | |||
463 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); | 462 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); |
464 | void dasd_alias_lcu_setup_complete(struct dasd_device *); | 463 | void dasd_alias_lcu_setup_complete(struct dasd_device *); |
465 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); | 464 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); |
465 | int 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 | ||
317 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 320 | extern 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 *); | |||
582 | void dasd_set_target_state(struct dasd_device *, int); | 586 | void dasd_set_target_state(struct dasd_device *, int); |
583 | void dasd_kick_device(struct dasd_device *); | 587 | void dasd_kick_device(struct dasd_device *); |
584 | void dasd_restore_device(struct dasd_device *); | 588 | void dasd_restore_device(struct dasd_device *); |
589 | void dasd_reload_device(struct dasd_device *); | ||
585 | 590 | ||
586 | void dasd_add_request_head(struct dasd_ccw_req *); | 591 | void dasd_add_request_head(struct dasd_ccw_req *); |
587 | void dasd_add_request_tail(struct dasd_ccw_req *); | 592 | void dasd_add_request_tail(struct dasd_ccw_req *); |