aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c109
-rw-r--r--drivers/s390/block/dasd_devmap.c1
-rw-r--r--drivers/s390/block/dasd_eckd.c108
-rw-r--r--drivers/s390/block/dasd_fba.c6
-rw-r--r--drivers/s390/block/dasd_int.h13
5 files changed, 218 insertions, 19 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 442bb98a2821..e5b84db0aa03 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -5,8 +5,7 @@
5 * Carsten Otte <Cotte@de.ibm.com> 5 * Carsten Otte <Cotte@de.ibm.com>
6 * Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Bugreports.to..: <Linux390@de.ibm.com> 7 * Bugreports.to..: <Linux390@de.ibm.com>
8 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 8 * Copyright IBM Corp. 1999, 2009
9 *
10 */ 9 */
11 10
12#define KMSG_COMPONENT "dasd" 11#define KMSG_COMPONENT "dasd"
@@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *);
61static void dasd_device_tasklet(struct dasd_device *); 60static void dasd_device_tasklet(struct dasd_device *);
62static void dasd_block_tasklet(struct dasd_block *); 61static void dasd_block_tasklet(struct dasd_block *);
63static void do_kick_device(struct work_struct *); 62static void do_kick_device(struct work_struct *);
63static void do_restore_device(struct work_struct *);
64static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); 64static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
65static void dasd_device_timeout(unsigned long); 65static void dasd_device_timeout(unsigned long);
66static void dasd_block_timeout(unsigned long); 66static void dasd_block_timeout(unsigned long);
@@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void)
109 device->timer.function = dasd_device_timeout; 109 device->timer.function = dasd_device_timeout;
110 device->timer.data = (unsigned long) device; 110 device->timer.data = (unsigned long) device;
111 INIT_WORK(&device->kick_work, do_kick_device); 111 INIT_WORK(&device->kick_work, do_kick_device);
112 INIT_WORK(&device->restore_device, do_restore_device);
112 device->state = DASD_STATE_NEW; 113 device->state = DASD_STATE_NEW;
113 device->target = DASD_STATE_NEW; 114 device->target = DASD_STATE_NEW;
114 115
@@ -512,6 +513,25 @@ void dasd_kick_device(struct dasd_device *device)
512} 513}
513 514
514/* 515/*
516 * dasd_restore_device will schedule a call do do_restore_device to the kernel
517 * event daemon.
518 */
519static void do_restore_device(struct work_struct *work)
520{
521 struct dasd_device *device = container_of(work, struct dasd_device,
522 restore_device);
523 device->cdev->drv->restore(device->cdev);
524 dasd_put_device(device);
525}
526
527void dasd_restore_device(struct dasd_device *device)
528{
529 dasd_get_device(device);
530 /* queue call to dasd_restore_device to the kernel event daemon. */
531 schedule_work(&device->restore_device);
532}
533
534/*
515 * Set the target state for a device and starts the state change. 535 * Set the target state for a device and starts the state change.
516 */ 536 */
517void dasd_set_target_state(struct dasd_device *device, int target) 537void dasd_set_target_state(struct dasd_device *device, int target)
@@ -908,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
908 DBF_DEV_EVENT(DBF_DEBUG, device, "%s", 928 DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
909 "start_IO: -EIO device gone, retry"); 929 "start_IO: -EIO device gone, retry");
910 break; 930 break;
931 case -EINVAL:
932 /* most likely caused in power management context */
933 DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
934 "start_IO: -EINVAL device currently "
935 "not accessible");
936 break;
911 default: 937 default:
912 /* internal error 11 - unknown rc */ 938 /* internal error 11 - unknown rc */
913 snprintf(errorstring, ERRORLENGTH, "11 %d", rc); 939 snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
@@ -2400,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
2400 case CIO_OPER: 2426 case CIO_OPER:
2401 /* FIXME: add a sanity check. */ 2427 /* FIXME: add a sanity check. */
2402 device->stopped &= ~DASD_STOPPED_DC_WAIT; 2428 device->stopped &= ~DASD_STOPPED_DC_WAIT;
2429 if (device->stopped & DASD_UNRESUMED_PM) {
2430 device->stopped &= ~DASD_UNRESUMED_PM;
2431 dasd_restore_device(device);
2432 ret = 1;
2433 break;
2434 }
2403 dasd_schedule_device_bh(device); 2435 dasd_schedule_device_bh(device);
2404 if (device->block) 2436 if (device->block)
2405 dasd_schedule_block_bh(device->block); 2437 dasd_schedule_block_bh(device->block);
@@ -2410,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
2410 return ret; 2442 return ret;
2411} 2443}
2412 2444
2445int dasd_generic_pm_freeze(struct ccw_device *cdev)
2446{
2447 struct dasd_ccw_req *cqr, *n;
2448 int rc;
2449 struct list_head freeze_queue;
2450 struct dasd_device *device = dasd_device_from_cdev(cdev);
2451
2452 if (IS_ERR(device))
2453 return PTR_ERR(device);
2454 /* disallow new I/O */
2455 device->stopped |= DASD_STOPPED_PM;
2456 /* clear active requests */
2457 INIT_LIST_HEAD(&freeze_queue);
2458 spin_lock_irq(get_ccwdev_lock(cdev));
2459 rc = 0;
2460 list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
2461 /* Check status and move request to flush_queue */
2462 if (cqr->status == DASD_CQR_IN_IO) {
2463 rc = device->discipline->term_IO(cqr);
2464 if (rc) {
2465 /* unable to terminate requeust */
2466 dev_err(&device->cdev->dev,
2467 "Unable to terminate request %p "
2468 "on suspend\n", cqr);
2469 spin_unlock_irq(get_ccwdev_lock(cdev));
2470 dasd_put_device(device);
2471 return rc;
2472 }
2473 }
2474 list_move_tail(&cqr->devlist, &freeze_queue);
2475 }
2476
2477 spin_unlock_irq(get_ccwdev_lock(cdev));
2478
2479 list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) {
2480 wait_event(dasd_flush_wq,
2481 (cqr->status != DASD_CQR_CLEAR_PENDING));
2482 if (cqr->status == DASD_CQR_CLEARED)
2483 cqr->status = DASD_CQR_QUEUED;
2484 }
2485 /* move freeze_queue to start of the ccw_queue */
2486 spin_lock_irq(get_ccwdev_lock(cdev));
2487 list_splice_tail(&freeze_queue, &device->ccw_queue);
2488 spin_unlock_irq(get_ccwdev_lock(cdev));
2489
2490 if (device->discipline->freeze)
2491 rc = device->discipline->freeze(device);
2492
2493 dasd_put_device(device);
2494 return rc;
2495}
2496EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze);
2497
2498int dasd_generic_restore_device(struct ccw_device *cdev)
2499{
2500 struct dasd_device *device = dasd_device_from_cdev(cdev);
2501 int rc = 0;
2502
2503 if (IS_ERR(device))
2504 return PTR_ERR(device);
2505
2506 dasd_schedule_device_bh(device);
2507 if (device->block)
2508 dasd_schedule_block_bh(device->block);
2509
2510 if (device->discipline->restore)
2511 rc = device->discipline->restore(device);
2512
2513 dasd_put_device(device);
2514 return rc;
2515}
2516EXPORT_SYMBOL_GPL(dasd_generic_restore_device);
2517
2413static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, 2518static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
2414 void *rdc_buffer, 2519 void *rdc_buffer,
2415 int rdc_buffer_size, 2520 int rdc_buffer_size,
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index e77666c8e6c0..4cac5b54f26a 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
1098 spin_unlock(&dasd_devmap_lock); 1098 spin_unlock(&dasd_devmap_lock);
1099 return 0; 1099 return 0;
1100} 1100}
1101EXPORT_SYMBOL_GPL(dasd_get_uid);
1101 1102
1102/* 1103/*
1103 * Register the given device unique identifier into devmap struct. 1104 * Register the given device unique identifier into devmap struct.
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index cf0cfdba1244..1c28ec3e4ccb 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -5,10 +5,9 @@
5 * Carsten Otte <Cotte@de.ibm.com> 5 * Carsten Otte <Cotte@de.ibm.com>
6 * Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Bugreports.to..: <Linux390@de.ibm.com> 7 * Bugreports.to..: <Linux390@de.ibm.com>
8 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 8 * Copyright IBM Corp. 1999, 2009
9 * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 9 * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
10 * Author.........: Nigel Hislop <hislop_nigel@emc.com> 10 * Author.........: Nigel Hislop <hislop_nigel@emc.com>
11 *
12 */ 11 */
13 12
14#define KMSG_COMPONENT "dasd" 13#define KMSG_COMPONENT "dasd"
@@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev)
104 return dasd_generic_set_online(cdev, &dasd_eckd_discipline); 103 return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
105} 104}
106 105
107static struct ccw_driver dasd_eckd_driver = {
108 .name = "dasd-eckd",
109 .owner = THIS_MODULE,
110 .ids = dasd_eckd_ids,
111 .probe = dasd_eckd_probe,
112 .remove = dasd_generic_remove,
113 .set_offline = dasd_generic_set_offline,
114 .set_online = dasd_eckd_set_online,
115 .notify = dasd_generic_notify,
116};
117
118static const int sizes_trk0[] = { 28, 148, 84 }; 106static const int sizes_trk0[] = { 28, 148, 84 };
119#define LABEL_SIZE 140 107#define LABEL_SIZE 140
120 108
@@ -3236,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
3236 dasd_eckd_dump_sense_ccw(device, req, irb); 3224 dasd_eckd_dump_sense_ccw(device, req, irb);
3237} 3225}
3238 3226
3227int dasd_eckd_pm_freeze(struct dasd_device *device)
3228{
3229 /*
3230 * the device should be disconnected from our LCU structure
3231 * on restore we will reconnect it and reread LCU specific
3232 * information like PAV support that might have changed
3233 */
3234 dasd_alias_remove_device(device);
3235 dasd_alias_disconnect_device_from_lcu(device);
3236
3237 return 0;
3238}
3239
3240int dasd_eckd_restore_device(struct dasd_device *device)
3241{
3242 struct dasd_eckd_private *private;
3243 int is_known, rc;
3244 struct dasd_uid temp_uid;
3245
3246 /* allow new IO again */
3247 device->stopped &= ~DASD_STOPPED_PM;
3248
3249 private = (struct dasd_eckd_private *) device->private;
3250
3251 /* Read Configuration Data */
3252 rc = dasd_eckd_read_conf(device);
3253 if (rc)
3254 goto out_err;
3255
3256 /* Generate device unique id and register in devmap */
3257 rc = dasd_eckd_generate_uid(device, &private->uid);
3258 dasd_get_uid(device->cdev, &temp_uid);
3259 if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
3260 dev_err(&device->cdev->dev, "The UID of the DASD has changed\n");
3261 if (rc)
3262 goto out_err;
3263 dasd_set_uid(device->cdev, &private->uid);
3264
3265 /* register lcu with alias handling, enable PAV if this is a new lcu */
3266 is_known = dasd_alias_make_device_known_to_lcu(device);
3267 if (is_known < 0)
3268 return is_known;
3269 if (!is_known) {
3270 /* new lcu found */
3271 rc = dasd_eckd_validate_server(device); /* will switch pav on */
3272 if (rc)
3273 goto out_err;
3274 }
3275
3276 /* Read Feature Codes */
3277 rc = dasd_eckd_read_features(device);
3278 if (rc)
3279 goto out_err;
3280
3281 /* Read Device Characteristics */
3282 memset(&private->rdc_data, 0, sizeof(private->rdc_data));
3283 rc = dasd_generic_read_dev_chars(device, "ECKD",
3284 &private->rdc_data, 64);
3285 if (rc) {
3286 DBF_EVENT(DBF_WARNING,
3287 "Read device characteristics failed, rc=%d for "
3288 "device: %s", rc, dev_name(&device->cdev->dev));
3289 goto out_err;
3290 }
3291
3292 /* add device to alias management */
3293 dasd_alias_add_device(device);
3294
3295 return 0;
3296
3297out_err:
3298 /*
3299 * if the resume failed for the DASD we put it in
3300 * an UNRESUMED stop state
3301 */
3302 device->stopped |= DASD_UNRESUMED_PM;
3303 return 0;
3304}
3305
3306static struct ccw_driver dasd_eckd_driver = {
3307 .name = "dasd-eckd",
3308 .owner = THIS_MODULE,
3309 .ids = dasd_eckd_ids,
3310 .probe = dasd_eckd_probe,
3311 .remove = dasd_generic_remove,
3312 .set_offline = dasd_generic_set_offline,
3313 .set_online = dasd_eckd_set_online,
3314 .notify = dasd_generic_notify,
3315 .freeze = dasd_generic_pm_freeze,
3316 .thaw = dasd_generic_restore_device,
3317 .restore = dasd_generic_restore_device,
3318};
3239 3319
3240/* 3320/*
3241 * max_blocks is dependent on the amount of storage that is available 3321 * max_blocks is dependent on the amount of storage that is available
@@ -3274,6 +3354,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
3274 .dump_sense_dbf = dasd_eckd_dump_sense_dbf, 3354 .dump_sense_dbf = dasd_eckd_dump_sense_dbf,
3275 .fill_info = dasd_eckd_fill_info, 3355 .fill_info = dasd_eckd_fill_info,
3276 .ioctl = dasd_eckd_ioctl, 3356 .ioctl = dasd_eckd_ioctl,
3357 .freeze = dasd_eckd_pm_freeze,
3358 .restore = dasd_eckd_restore_device,
3277}; 3359};
3278 3360
3279static int __init 3361static int __init
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 597c6ffdb9f2..e21ee735f926 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -2,8 +2,7 @@
2 * File...........: linux/drivers/s390/block/dasd_fba.c 2 * File...........: linux/drivers/s390/block/dasd_fba.c
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> 3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 * Bugreports.to..: <Linux390@de.ibm.com> 4 * Bugreports.to..: <Linux390@de.ibm.com>
5 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 5 * Copyright IBM Corp. 1999, 2009
6 *
7 */ 6 */
8 7
9#define KMSG_COMPONENT "dasd" 8#define KMSG_COMPONENT "dasd"
@@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = {
75 .set_offline = dasd_generic_set_offline, 74 .set_offline = dasd_generic_set_offline,
76 .set_online = dasd_fba_set_online, 75 .set_online = dasd_fba_set_online,
77 .notify = dasd_generic_notify, 76 .notify = dasd_generic_notify,
77 .freeze = dasd_generic_pm_freeze,
78 .thaw = dasd_generic_restore_device,
79 .restore = dasd_generic_restore_device,
78}; 80};
79 81
80static void 82static void
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index f97ceb795078..fd63b2f2bda9 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -4,8 +4,7 @@
4 * Horst Hummel <Horst.Hummel@de.ibm.com> 4 * Horst Hummel <Horst.Hummel@de.ibm.com>
5 * Martin Schwidefsky <schwidefsky@de.ibm.com> 5 * Martin Schwidefsky <schwidefsky@de.ibm.com>
6 * Bugreports.to..: <Linux390@de.ibm.com> 6 * Bugreports.to..: <Linux390@de.ibm.com>
7 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 7 * Copyright IBM Corp. 1999, 2009
8 *
9 */ 8 */
10 9
11#ifndef DASD_INT_H 10#ifndef DASD_INT_H
@@ -295,6 +294,10 @@ struct dasd_discipline {
295 int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); 294 int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
296 int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); 295 int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
297 int (*ioctl) (struct dasd_block *, unsigned int, void __user *); 296 int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
297
298 /* suspend/resume functions */
299 int (*freeze) (struct dasd_device *);
300 int (*restore) (struct dasd_device *);
298}; 301};
299 302
300extern struct dasd_discipline *dasd_diag_discipline_pointer; 303extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -367,6 +370,7 @@ struct dasd_device {
367 atomic_t tasklet_scheduled; 370 atomic_t tasklet_scheduled;
368 struct tasklet_struct tasklet; 371 struct tasklet_struct tasklet;
369 struct work_struct kick_work; 372 struct work_struct kick_work;
373 struct work_struct restore_device;
370 struct timer_list timer; 374 struct timer_list timer;
371 375
372 debug_info_t *debug_area; 376 debug_info_t *debug_area;
@@ -410,6 +414,8 @@ struct dasd_block {
410#define DASD_STOPPED_PENDING 4 /* long busy */ 414#define DASD_STOPPED_PENDING 4 /* long busy */
411#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ 415#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */
412#define DASD_STOPPED_SU 16 /* summary unit check handling */ 416#define DASD_STOPPED_SU 16 /* summary unit check handling */
417#define DASD_STOPPED_PM 32 /* pm state transition */
418#define DASD_UNRESUMED_PM 64 /* pm resume failed state */
413 419
414/* per device flags */ 420/* per device flags */
415#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ 421#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */
@@ -556,6 +562,7 @@ void dasd_free_block(struct dasd_block *);
556void dasd_enable_device(struct dasd_device *); 562void dasd_enable_device(struct dasd_device *);
557void dasd_set_target_state(struct dasd_device *, int); 563void dasd_set_target_state(struct dasd_device *, int);
558void dasd_kick_device(struct dasd_device *); 564void dasd_kick_device(struct dasd_device *);
565void dasd_restore_device(struct dasd_device *);
559 566
560void dasd_add_request_head(struct dasd_ccw_req *); 567void dasd_add_request_head(struct dasd_ccw_req *);
561void dasd_add_request_tail(struct dasd_ccw_req *); 568void dasd_add_request_tail(struct dasd_ccw_req *);
@@ -578,6 +585,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
578int dasd_generic_set_offline (struct ccw_device *cdev); 585int dasd_generic_set_offline (struct ccw_device *cdev);
579int dasd_generic_notify(struct ccw_device *, int); 586int dasd_generic_notify(struct ccw_device *, int);
580void dasd_generic_handle_state_change(struct dasd_device *); 587void dasd_generic_handle_state_change(struct dasd_device *);
588int dasd_generic_pm_freeze(struct ccw_device *);
589int dasd_generic_restore_device(struct ccw_device *);
581 590
582int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); 591int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
583char *dasd_get_sense(struct irb *); 592char *dasd_get_sense(struct irb *);