aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/hw_random/s390-trng.c7
-rw-r--r--drivers/s390/block/dasd.c93
-rw-r--r--drivers/s390/block/dasd_eckd.c94
-rw-r--r--drivers/s390/block/dasd_fba.c3
-rw-r--r--drivers/s390/block/dasd_int.h10
-rw-r--r--drivers/s390/char/con3215.c85
-rw-r--r--drivers/s390/char/con3270.c1
-rw-r--r--drivers/s390/char/raw3270.c78
-rw-r--r--drivers/s390/char/raw3270.h1
-rw-r--r--drivers/s390/char/sclp.h10
-rw-r--r--drivers/s390/char/sclp_cmd.c16
-rw-r--r--drivers/s390/char/sclp_early.c59
-rw-r--r--drivers/s390/char/sclp_early_core.c13
-rw-r--r--drivers/s390/char/tape.h1
-rw-r--r--drivers/s390/char/tape_34xx.c1
-rw-r--r--drivers/s390/char/tape_3590.c1
-rw-r--r--drivers/s390/char/tape_core.c50
-rw-r--r--drivers/s390/char/vmur.c24
-rw-r--r--drivers/s390/cio/chsc_sch.c29
-rw-r--r--drivers/s390/cio/cmf.c5
-rw-r--r--drivers/s390/cio/css.c130
-rw-r--r--drivers/s390/cio/css.h10
-rw-r--r--drivers/s390/cio/device.c265
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c6
-rw-r--r--drivers/s390/cio/eadm_sch.c13
-rw-r--r--drivers/s390/cio/io_sch.h1
-rw-r--r--drivers/s390/crypto/ap_bus.c213
-rw-r--r--drivers/s390/crypto/ap_bus.h12
-rw-r--r--drivers/s390/crypto/pkey_api.c15
-rw-r--r--drivers/s390/crypto/zcrypt_api.c66
-rw-r--r--drivers/s390/crypto/zcrypt_api.h2
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c57
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c25
-rw-r--r--drivers/s390/scsi/zfcp_def.h1
-rw-r--r--drivers/s390/scsi/zfcp_ext.h1
36 files changed, 359 insertions, 1040 deletions
diff --git a/drivers/char/hw_random/s390-trng.c b/drivers/char/hw_random/s390-trng.c
index 413cacbb08e2..7c673afd7241 100644
--- a/drivers/char/hw_random/s390-trng.c
+++ b/drivers/char/hw_random/s390-trng.c
@@ -192,14 +192,15 @@ static int trng_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
/*
* hwrng register struct
- * The trng is suppost to have 100% entropy, and thus
- * we register with a very high quality value.
+ * The trng is supposed to have 100% entropy, and thus we register with a very
+ * high quality value. If we ever have a better driver in the future, we should
+ * change this value again when we merge this driver.
*/
static struct hwrng trng_hwrng_dev = {
.name = "s390-trng",
.data_read = trng_hwrng_data_read,
.read = trng_hwrng_read,
- .quality = 999,
+ .quality = 1024,
};
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 217a7b84abdf..fd568248fd26 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -75,7 +75,6 @@ static int dasd_flush_block_queue(struct dasd_block *);
static void dasd_device_tasklet(unsigned long);
static void dasd_block_tasklet(unsigned long);
static void do_kick_device(struct work_struct *);
-static void do_restore_device(struct work_struct *);
static void do_reload_device(struct work_struct *);
static void do_requeue_requests(struct work_struct *);
static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
@@ -138,7 +137,6 @@ struct dasd_device *dasd_alloc_device(void)
INIT_LIST_HEAD(&device->ccw_queue);
timer_setup(&device->timer, dasd_device_timeout, 0);
INIT_WORK(&device->kick_work, do_kick_device);
- INIT_WORK(&device->restore_device, do_restore_device);
INIT_WORK(&device->reload_device, do_reload_device);
INIT_WORK(&device->requeue_requests, do_requeue_requests);
device->state = DASD_STATE_NEW;
@@ -621,26 +619,6 @@ void dasd_reload_device(struct dasd_device *device)
EXPORT_SYMBOL(dasd_reload_device);
/*
- * dasd_restore_device will schedule a call do do_restore_device to the kernel
- * event daemon.
- */
-static void do_restore_device(struct work_struct *work)
-{
- struct dasd_device *device = container_of(work, struct dasd_device,
- restore_device);
- device->cdev->drv->restore(device->cdev);
- dasd_put_device(device);
-}
-
-void dasd_restore_device(struct dasd_device *device)
-{
- dasd_get_device(device);
- /* queue call to dasd_restore_device to the kernel event daemon. */
- if (!schedule_work(&device->restore_device))
- dasd_put_device(device);
-}
-
-/*
* Set the target state for a device and starts the state change.
*/
void dasd_set_target_state(struct dasd_device *device, int target)
@@ -1514,7 +1492,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
"start_IO: -EIO device gone, retry");
break;
case -EINVAL:
- /* most likely caused in power management context */
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: -EINVAL device currently "
"not accessible");
@@ -2048,7 +2025,7 @@ static void __dasd_device_check_expire(struct dasd_device *device)
static int __dasd_device_is_unusable(struct dasd_device *device,
struct dasd_ccw_req *cqr)
{
- int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM | DASD_STOPPED_NOSPC);
+ int mask = ~(DASD_STOPPED_DC_WAIT | DASD_STOPPED_NOSPC);
if (test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
!test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
@@ -2112,8 +2089,7 @@ static void __dasd_device_check_path_events(struct dasd_device *device)
if (!dasd_path_get_tbvpm(device))
return;
- if (device->stopped &
- ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM))
+ if (device->stopped & ~(DASD_STOPPED_DC_WAIT))
return;
rc = device->discipline->verify_path(device,
dasd_path_get_tbvpm(device));
@@ -3794,11 +3770,6 @@ int dasd_generic_path_operational(struct dasd_device *device)
"operational\n");
DBF_DEV_EVENT(DBF_WARNING, device, "%s", "path operational");
dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT);
- if (device->stopped & DASD_UNRESUMED_PM) {
- dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM);
- dasd_restore_device(device);
- return 1;
- }
dasd_schedule_device_bh(device);
if (device->block) {
dasd_schedule_block_bh(device->block);
@@ -4058,66 +4029,6 @@ void dasd_schedule_requeue(struct dasd_device *device)
}
EXPORT_SYMBOL(dasd_schedule_requeue);
-int dasd_generic_pm_freeze(struct ccw_device *cdev)
-{
- struct dasd_device *device = dasd_device_from_cdev(cdev);
-
- if (IS_ERR(device))
- return PTR_ERR(device);
-
- /* mark device as suspended */
- set_bit(DASD_FLAG_SUSPENDED, &device->flags);
-
- if (device->discipline->freeze)
- device->discipline->freeze(device);
-
- /* disallow new I/O */
- dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
-
- return dasd_generic_requeue_all_requests(device);
-}
-EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze);
-
-int dasd_generic_restore_device(struct ccw_device *cdev)
-{
- struct dasd_device *device = dasd_device_from_cdev(cdev);
- int rc = 0;
-
- if (IS_ERR(device))
- return PTR_ERR(device);
-
- /* allow new IO again */
- dasd_device_remove_stop_bits(device,
- (DASD_STOPPED_PM | DASD_UNRESUMED_PM));
-
- dasd_schedule_device_bh(device);
-
- /*
- * call discipline restore function
- * if device is stopped do nothing e.g. for disconnected devices
- */
- if (device->discipline->restore && !(device->stopped))
- rc = device->discipline->restore(device);
- if (rc || device->stopped)
- /*
- * if the resume failed for the DASD we put it in
- * an UNRESUMED stop state
- */
- device->stopped |= DASD_UNRESUMED_PM;
-
- if (device->block) {
- dasd_schedule_block_bh(device->block);
- if (device->block->request_queue)
- blk_mq_run_hw_queues(device->block->request_queue,
- true);
- }
-
- clear_bit(DASD_FLAG_SUSPENDED, &device->flags);
- dasd_put_device(device);
- return 0;
-}
-EXPORT_SYMBOL_GPL(dasd_generic_restore_device);
-
static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
int rdc_buffer_size,
int magic)
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index ad44d22e8859..758ee4153ac1 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -5716,95 +5716,6 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
}
}
-static int dasd_eckd_pm_freeze(struct dasd_device *device)
-{
- /*
- * the device should be disconnected from our LCU structure
- * on restore we will reconnect it and reread LCU specific
- * information like PAV support that might have changed
- */
- dasd_alias_remove_device(device);
- dasd_alias_disconnect_device_from_lcu(device);
-
- return 0;
-}
-
-static int dasd_eckd_restore_device(struct dasd_device *device)
-{
- struct dasd_eckd_private *private = device->private;
- struct dasd_eckd_characteristics temp_rdc_data;
- int rc;
- struct dasd_uid temp_uid;
- unsigned long flags;
- unsigned long cqr_flags = 0;
-
- /* Read Configuration Data */
- rc = dasd_eckd_read_conf(device);
- if (rc) {
- DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
- "Read configuration data failed, rc=%d", rc);
- goto out_err;
- }
-
- dasd_eckd_get_uid(device, &temp_uid);
- /* Generate device unique id */
- rc = dasd_eckd_generate_uid(device);
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
- dev_err(&device->cdev->dev, "The UID of the DASD has "
- "changed\n");
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- if (rc)
- goto out_err;
-
- /* register lcu with alias handling, enable PAV if this is a new lcu */
- rc = dasd_alias_make_device_known_to_lcu(device);
- if (rc)
- goto out_err;
-
- set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr_flags);
- dasd_eckd_validate_server(device, cqr_flags);
-
- /* RE-Read Configuration Data */
- rc = dasd_eckd_read_conf(device);
- if (rc) {
- DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
- "Read configuration data failed, rc=%d", rc);
- goto out_err2;
- }
-
- /* Read Feature Codes */
- dasd_eckd_read_features(device);
-
- /* Read Volume Information */
- dasd_eckd_read_vol_info(device);
-
- /* Read Extent Pool Information */
- dasd_eckd_read_ext_pool_info(device);
-
- /* Read Device Characteristics */
- rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
- &temp_rdc_data, 64);
- if (rc) {
- DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
- "Read device characteristic failed, rc=%d", rc);
- goto out_err2;
- }
- spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- memcpy(&private->rdc_data, &temp_rdc_data, sizeof(temp_rdc_data));
- spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-
- /* add device to alias management */
- dasd_alias_add_device(device);
-
- return 0;
-
-out_err2:
- dasd_alias_disconnect_device_from_lcu(device);
-out_err:
- return -1;
-}
-
static int dasd_eckd_reload_device(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
@@ -6668,9 +6579,6 @@ static struct ccw_driver dasd_eckd_driver = {
.notify = dasd_generic_notify,
.path_event = dasd_generic_path_event,
.shutdown = dasd_generic_shutdown,
- .freeze = dasd_generic_pm_freeze,
- .thaw = dasd_generic_restore_device,
- .restore = dasd_generic_restore_device,
.uc_handler = dasd_generic_uc_handler,
.int_class = IRQIO_DAS,
};
@@ -6702,8 +6610,6 @@ static struct dasd_discipline dasd_eckd_discipline = {
.dump_sense_dbf = dasd_eckd_dump_sense_dbf,
.fill_info = dasd_eckd_fill_info,
.ioctl = dasd_eckd_ioctl,
- .freeze = dasd_eckd_pm_freeze,
- .restore = dasd_eckd_restore_device,
.reload = dasd_eckd_reload_device,
.get_uid = dasd_eckd_get_uid,
.kick_validate = dasd_eckd_kick_validate_server,
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 1a44e321b54e..c027344ee225 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -79,9 +79,6 @@ static struct ccw_driver dasd_fba_driver = {
.set_online = dasd_fba_set_online,
.notify = dasd_generic_notify,
.path_event = dasd_generic_path_event,
- .freeze = dasd_generic_pm_freeze,
- .thaw = dasd_generic_restore_device,
- .restore = dasd_generic_restore_device,
.int_class = IRQIO_DAS,
};
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index fa552f9f1666..7a34161ea5c6 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -355,10 +355,6 @@ struct dasd_discipline {
int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
- /* suspend/resume functions */
- int (*freeze) (struct dasd_device *);
- int (*restore) (struct dasd_device *);
-
/* reload device after state change */
int (*reload) (struct dasd_device *);
@@ -520,7 +516,6 @@ struct dasd_device {
atomic_t tasklet_scheduled;
struct tasklet_struct tasklet;
struct work_struct kick_work;
- struct work_struct restore_device;
struct work_struct reload_device;
struct work_struct kick_validate;
struct work_struct suc_work;
@@ -592,8 +587,6 @@ struct dasd_queue {
#define DASD_STOPPED_PENDING 4 /* long busy */
#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */
#define DASD_STOPPED_SU 16 /* summary unit check handling */
-#define DASD_STOPPED_PM 32 /* pm state transition */
-#define DASD_UNRESUMED_PM 64 /* pm resume failed state */
#define DASD_STOPPED_NOSPC 128 /* no space left */
/* per device flags */
@@ -753,7 +746,6 @@ enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved);
void dasd_enable_device(struct dasd_device *);
void dasd_set_target_state(struct dasd_device *, int);
void dasd_kick_device(struct dasd_device *);
-void dasd_restore_device(struct dasd_device *);
void dasd_reload_device(struct dasd_device *);
void dasd_schedule_requeue(struct dasd_device *);
@@ -785,8 +777,6 @@ int dasd_generic_path_operational(struct dasd_device *);
void dasd_generic_shutdown(struct ccw_device *);
void dasd_generic_handle_state_change(struct dasd_device *);
-int dasd_generic_pm_freeze(struct ccw_device *);
-int dasd_generic_restore_device(struct ccw_device *);
enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
void dasd_generic_path_event(struct ccw_device *, int *);
int dasd_generic_verify_path(struct dasd_device *, __u8);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index d8acabbb1ed3..1354c42d95aa 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -289,16 +289,14 @@ static void raw3215_timeout(struct timer_list *t)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw->flags &= ~RAW3215_TIMER_RUNS;
- if (!tty_port_suspended(&raw->port)) {
- raw3215_mk_write_req(raw);
- raw3215_start_io(raw);
- if ((raw->queued_read || raw->queued_write) &&
- !(raw->flags & RAW3215_WORKING) &&
- !(raw->flags & RAW3215_TIMER_RUNS)) {
- raw->timer.expires = RAW3215_TIMEOUT + jiffies;
- add_timer(&raw->timer);
- raw->flags |= RAW3215_TIMER_RUNS;
- }
+ raw3215_mk_write_req(raw);
+ raw3215_start_io(raw);
+ if ((raw->queued_read || raw->queued_write) &&
+ !(raw->flags & RAW3215_WORKING) &&
+ !(raw->flags & RAW3215_TIMER_RUNS)) {
+ raw->timer.expires = RAW3215_TIMEOUT + jiffies;
+ add_timer(&raw->timer);
+ raw->flags |= RAW3215_TIMER_RUNS;
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
@@ -311,7 +309,7 @@ static void raw3215_timeout(struct timer_list *t)
*/
static inline void raw3215_try_io(struct raw3215_info *raw)
{
- if (!tty_port_initialized(&raw->port) || tty_port_suspended(&raw->port))
+ if (!tty_port_initialized(&raw->port))
return;
if (raw->queued_read != NULL)
raw3215_start_io(raw);
@@ -464,26 +462,6 @@ put_tty:
}
/*
- * Drop the oldest line from the output buffer.
- */
-static void raw3215_drop_line(struct raw3215_info *raw)
-{
- int ix;
- char ch;
-
- BUG_ON(raw->written != 0);
- ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1);
- while (raw->count > 0) {
- ch = raw->buffer[ix];
- ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
- raw->count--;
- if (ch == 0x15)
- break;
- }
- raw->head = ix;
-}
-
-/*
* Wait until length bytes are available int the output buffer.
* Has to be called with the s390irq lock held. Can be called
* disabled.
@@ -491,13 +469,6 @@ static void raw3215_drop_line(struct raw3215_info *raw)
static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
{
while (RAW3215_BUFFER_SIZE - raw->count < length) {
- /* While console is frozen for suspend we have no other
- * choice but to drop message from the buffer to make
- * room for even more messages. */
- if (tty_port_suspended(&raw->port)) {
- raw3215_drop_line(raw);
- continue;
- }
/* there might be a request pending */
raw->flags |= RAW3215_FLUSHING;
raw3215_mk_write_req(raw);
@@ -763,36 +734,6 @@ static int raw3215_set_offline (struct ccw_device *cdev)
return 0;
}
-static int raw3215_pm_stop(struct ccw_device *cdev)
-{
- struct raw3215_info *raw;
- unsigned long flags;
-
- /* Empty the output buffer, then prevent new I/O. */
- raw = dev_get_drvdata(&cdev->dev);
- spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
- raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
- tty_port_set_suspended(&raw->port, 1);
- spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
- return 0;
-}
-
-static int raw3215_pm_start(struct ccw_device *cdev)
-{
- struct raw3215_info *raw;
- unsigned long flags;
-
- /* Allow I/O again and flush output buffer. */
- raw = dev_get_drvdata(&cdev->dev);
- spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
- tty_port_set_suspended(&raw->port, 0);
- raw->flags |= RAW3215_FLUSHING;
- raw3215_try_io(raw);
- raw->flags &= ~RAW3215_FLUSHING;
- spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
- return 0;
-}
-
static struct ccw_device_id raw3215_id[] = {
{ CCW_DEVICE(0x3215, 0) },
{ /* end of list */ },
@@ -808,9 +749,6 @@ static struct ccw_driver raw3215_ccw_driver = {
.remove = &raw3215_remove,
.set_online = &raw3215_set_online,
.set_offline = &raw3215_set_offline,
- .freeze = &raw3215_pm_stop,
- .thaw = &raw3215_pm_start,
- .restore = &raw3215_pm_start,
.int_class = IRQIO_C15,
};
@@ -858,11 +796,6 @@ static void con3215_flush(void)
unsigned long flags;
raw = raw3215[0]; /* console 3215 is the first one */
- if (tty_port_suspended(&raw->port))
- /* The console is still frozen for suspend. */
- if (ccw_device_force_console(raw->cdev))
- /* Forcing didn't work, no panic message .. */
- return;
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index e17364e13d2f..e21962c0fd94 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -544,7 +544,6 @@ con3270_flush(void)
cp = condev;
if (!cp->view.dev)
return;
- raw3270_pm_unfreeze(&cp->view);
raw3270_activate_view(&cp->view);
spin_lock_irqsave(&cp->view.lock, flags);
con3270_wait_write(cp);
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 63a41b168761..646ec796bb83 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -67,7 +67,6 @@ struct raw3270 {
#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
#define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
-#define RAW3270_FLAGS_FROZEN 3 /* set if 3270 is frozen for suspend */
/* Semaphore to protect global data of raw3270 (devices, views, etc). */
static DEFINE_MUTEX(raw3270_mutex);
@@ -260,8 +259,7 @@ raw3270_view_active(struct raw3270_view *view)
{
struct raw3270 *rp = view->dev;
- return rp && rp->view == view &&
- !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+ return rp && rp->view == view;
}
int
@@ -273,8 +271,7 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
rp = view->dev;
- if (!rp || rp->view != view ||
- test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+ if (!rp || rp->view != view)
rc = -EACCES;
else if (!raw3270_state_ready(rp))
rc = -EBUSY;
@@ -291,8 +288,7 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
int rc;
rp = view->dev;
- if (!rp || rp->view != view ||
- test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+ if (!rp || rp->view != view)
rc = -EACCES;
else if (!raw3270_state_ready(rp))
rc = -EBUSY;
@@ -629,8 +625,7 @@ raw3270_reset(struct raw3270_view *view)
int rc;
rp = view->dev;
- if (!rp || rp->view != view ||
- test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+ if (!rp || rp->view != view)
rc = -EACCES;
else if (!raw3270_state_ready(rp))
rc = -EBUSY;
@@ -854,8 +849,6 @@ raw3270_activate_view(struct raw3270_view *view)
rc = 0;
else if (!raw3270_state_ready(rp))
rc = -EBUSY;
- else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
- rc = -EACCES;
else {
oldview = NULL;
if (rp->view && rp->view->fn->deactivate) {
@@ -903,8 +896,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
list_del_init(&view->list);
list_add_tail(&view->list, &rp->view_list);
/* Try to activate another view. */
- if (raw3270_state_ready(rp) &&
- !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
+ if (raw3270_state_ready(rp)) {
list_for_each_entry(view, &rp->view_list, list) {
rp->view = view;
if (view->fn->activate(view) == 0)
@@ -999,8 +991,7 @@ raw3270_del_view(struct raw3270_view *view)
rp->view = NULL;
}
list_del_init(&view->list);
- if (!rp->view && raw3270_state_ready(rp) &&
- !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
+ if (!rp->view && raw3270_state_ready(rp)) {
/* Try to activate another view. */
list_for_each_entry(nv, &rp->view_list, list) {
if (nv->fn->activate(nv) == 0) {
@@ -1215,60 +1206,6 @@ raw3270_set_offline (struct ccw_device *cdev)
return 0;
}
-static int raw3270_pm_stop(struct ccw_device *cdev)
-{
- struct raw3270 *rp;
- struct raw3270_view *view;
- unsigned long flags;
-
- rp = dev_get_drvdata(&cdev->dev);
- if (!rp)
- return 0;
- spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
- if (rp->view && rp->view->fn->deactivate)
- rp->view->fn->deactivate(rp->view);
- if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
- /*
- * Release tty and fullscreen for all non-console
- * devices.
- */
- list_for_each_entry(view, &rp->view_list, list) {
- if (view->fn->release)
- view->fn->release(view);
- }
- }
- set_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
- spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
- return 0;
-}
-
-static int raw3270_pm_start(struct ccw_device *cdev)
-{
- struct raw3270 *rp;
- unsigned long flags;
-
- rp = dev_get_drvdata(&cdev->dev);
- if (!rp)
- return 0;
- spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
- clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
- if (rp->view && rp->view->fn->activate)
- rp->view->fn->activate(rp->view);
- spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
- return 0;
-}
-
-void raw3270_pm_unfreeze(struct raw3270_view *view)
-{
-#ifdef CONFIG_TN3270_CONSOLE
- struct raw3270 *rp;
-
- rp = view->dev;
- if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
- ccw_device_force_console(rp->cdev);
-#endif
-}
-
static struct ccw_device_id raw3270_id[] = {
{ CCW_DEVICE(0x3270, 0) },
{ CCW_DEVICE(0x3271, 0) },
@@ -1294,9 +1231,6 @@ static struct ccw_driver raw3270_ccw_driver = {
.remove = &raw3270_remove,
.set_online = &raw3270_set_online,
.set_offline = &raw3270_set_offline,
- .freeze = &raw3270_pm_stop,
- .thaw = &raw3270_pm_start,
- .restore = &raw3270_pm_start,
.int_class = IRQIO_C70,
};
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index 8d979e0ee605..c6645167cd2b 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -199,7 +199,6 @@ struct raw3270_notifier {
int raw3270_register_notifier(struct raw3270_notifier *);
void raw3270_unregister_notifier(struct raw3270_notifier *);
-void raw3270_pm_unfreeze(struct raw3270_view *);
/*
* Little memory allocator for string objects.
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 69d9cde9ff5a..6de919944a39 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -156,7 +156,11 @@ struct read_cpu_info_sccb {
u16 offset_configured;
u16 nr_standby;
u16 offset_standby;
- u8 reserved[4096 - 16];
+ /*
+ * Without ext sccb, struct size is PAGE_SIZE.
+ * With ext sccb, struct size is EXT_SCCB_READ_CPU.
+ */
+ u8 reserved[];
} __attribute__((packed, aligned(PAGE_SIZE)));
struct read_info_sccb {
@@ -199,7 +203,7 @@ struct read_info_sccb {
u8 byte_134; /* 134 */
u8 cpudirq; /* 135 */
u16 cbl; /* 136-137 */
- u8 _pad_138[4096 - 138]; /* 138-4095 */
+ u8 _pad_138[EXT_SCCB_READ_SCP - 138];
} __packed __aligned(PAGE_SIZE);
struct read_storage_sccb {
@@ -328,7 +332,7 @@ unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb);
int sclp_early_set_event_mask(struct init_sccb *sccb,
sccb_mask_t receive_mask,
sccb_mask_t send_mask);
-int sclp_early_get_info(struct read_info_sccb *info);
+struct read_info_sccb * __init sclp_early_get_info(void);
/* useful inlines */
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index f6e97f0830f6..d41bc144c183 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -27,6 +27,7 @@
#include <asm/page.h>
#include <asm/sclp.h>
#include <asm/numa.h>
+#include <asm/facility.h>
#include "sclp.h"
@@ -87,14 +88,17 @@ out:
int _sclp_get_core_info(struct sclp_core_info *info)
{
int rc;
+ int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
struct read_cpu_info_sccb *sccb;
if (!SCLP_HAS_CPU_INFO)
return -EOPNOTSUPP;
- sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+
+ sccb = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA | __GFP_ZERO, get_order(length));
if (!sccb)
return -ENOMEM;
- sccb->header.length = sizeof(*sccb);
+ sccb->header.length = length;
+ sccb->header.control_mask[2] = 0x80;
rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb,
SCLP_QUEUE_INTERVAL);
if (rc)
@@ -107,7 +111,7 @@ int _sclp_get_core_info(struct sclp_core_info *info)
}
sclp_fill_core_info(info, sccb);
out:
- free_page((unsigned long) sccb);
+ free_pages((unsigned long) sccb, get_order(length));
return rc;
}
@@ -397,10 +401,10 @@ static void __init add_memory_merged(u16 rn)
goto skip_add;
if (start + size > VMEM_MAX_PHYS)
size = VMEM_MAX_PHYS - start;
- if (memory_end_set && (start >= memory_end))
+ if (start >= ident_map_size)
goto skip_add;
- if (memory_end_set && (start + size > memory_end))
- size = memory_end - start;
+ if (start + size > ident_map_size)
+ size = ident_map_size - start;
block_size = memory_block_size_bytes();
align_to_block_size(&start, &size, block_size);
if (!size)
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index cc5e84b80c69..2f3515fa242a 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -9,9 +9,12 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/errno.h>
+#include <linux/memblock.h>
#include <asm/ctl_reg.h>
#include <asm/sclp.h>
#include <asm/ipl.h>
+#include <asm/setup.h>
+#include <asm/facility.h>
#include "sclp_sdias.h"
#include "sclp.h"
@@ -20,12 +23,14 @@ static struct sclp_ipl_info sclp_ipl_info;
struct sclp_info sclp;
EXPORT_SYMBOL(sclp);
-static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
+static void __init sclp_early_facilities_detect(void)
{
struct sclp_core_entry *cpue;
+ struct read_info_sccb *sccb;
u16 boot_cpu_address, cpu;
- if (sclp_early_get_info(sccb))
+ sccb = sclp_early_get_info();
+ if (!sccb)
return;
sclp.facilities = sccb->facilities;
@@ -107,29 +112,34 @@ void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info)
*info = sclp_ipl_info;
}
-static struct sclp_core_info sclp_early_core_info __initdata;
-static int sclp_early_core_info_valid __initdata;
-
-static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb)
-{
- if (!SCLP_HAS_CPU_INFO)
- return;
- memset(sccb, 0, sizeof(*sccb));
- sccb->header.length = sizeof(*sccb);
- if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb))
- return;
- if (sccb->header.response_code != 0x0010)
- return;
- sclp_fill_core_info(&sclp_early_core_info, sccb);
- sclp_early_core_info_valid = 1;
-}
-
int __init sclp_early_get_core_info(struct sclp_core_info *info)
{
- if (!sclp_early_core_info_valid)
- return -EIO;
- *info = sclp_early_core_info;
- return 0;
+ struct read_cpu_info_sccb *sccb;
+ int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
+ int rc = 0;
+
+ if (!SCLP_HAS_CPU_INFO)
+ return -EOPNOTSUPP;
+
+ sccb = memblock_alloc_low(length, PAGE_SIZE);
+ if (!sccb)
+ return -ENOMEM;
+
+ memset(sccb, 0, length);
+ sccb->header.length = length;
+ sccb->header.control_mask[2] = 0x80;
+ if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb)) {
+ rc = -EIO;
+ goto out;
+ }
+ if (sccb->header.response_code != 0x0010) {
+ rc = -EIO;
+ goto out;
+ }
+ sclp_fill_core_info(info, sccb);
+out:
+ memblock_free_early((unsigned long)sccb, length);
+ return rc;
}
static void __init sclp_early_console_detect(struct init_sccb *sccb)
@@ -148,8 +158,7 @@ void __init sclp_early_detect(void)
{
void *sccb = sclp_early_sccb;
- sclp_early_facilities_detect(sccb);
- sclp_early_init_core_info(sccb);
+ sclp_early_facilities_detect();
/*
* Turn off SCLP event notifications. Also save remote masks in the
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c
index a960afa974bf..ec9f8ad5341c 100644
--- a/drivers/s390/char/sclp_early_core.c
+++ b/drivers/s390/char/sclp_early_core.c
@@ -11,6 +11,7 @@
#include <asm/irq.h>
#include <asm/sections.h>
#include <asm/mem_detect.h>
+#include <asm/facility.h>
#include "sclp.h"
#include "sclp_rw.h"
@@ -237,13 +238,14 @@ void sclp_early_printk(const char *str)
int __init sclp_early_read_info(void)
{
int i;
+ int length = test_facility(140) ? EXT_SCCB_READ_SCP : PAGE_SIZE;
struct read_info_sccb *sccb = &sclp_info_sccb;
sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
SCLP_CMDW_READ_SCP_INFO};
for (i = 0; i < ARRAY_SIZE(commands); i++) {
- memset(sccb, 0, sizeof(*sccb));
- sccb->header.length = sizeof(*sccb);
+ memset(sccb, 0, length);
+ sccb->header.length = length;
sccb->header.function_code = 0x80;
sccb->header.control_mask[2] = 0x80;
if (sclp_early_cmd(commands[i], sccb))
@@ -258,13 +260,12 @@ int __init sclp_early_read_info(void)
return -EIO;
}
-int __init sclp_early_get_info(struct read_info_sccb *info)
+struct read_info_sccb * __init sclp_early_get_info(void)
{
if (!sclp_info_sccb_valid)
- return -EIO;
+ return NULL;
- *info = sclp_info_sccb;
- return 0;
+ return &sclp_info_sccb;
}
int __init sclp_early_get_memsize(unsigned long *mem)
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index e2c60475dfa8..4e5d5efa978f 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -264,7 +264,6 @@ extern void tape_state_set(struct tape_device *, enum tape_state);
extern int tape_generic_online(struct tape_device *, struct tape_discipline *);
extern int tape_generic_offline(struct ccw_device *);
-extern int tape_generic_pm_suspend(struct ccw_device *);
/* Externals from tape_devmap.c */
extern int tape_generic_probe(struct ccw_device *);
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 6d73ee3f827a..7ada994d4592 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -1191,7 +1191,6 @@ static struct ccw_driver tape_34xx_driver = {
.remove = tape_generic_remove,
.set_online = tape_34xx_online,
.set_offline = tape_generic_offline,
- .freeze = tape_generic_pm_suspend,
.int_class = IRQIO_TAP,
};
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 4554cdf4d6bd..ecf8c5006a0e 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -1651,7 +1651,6 @@ static struct ccw_driver tape_3590_driver = {
.remove = tape_generic_remove,
.set_offline = tape_generic_offline,
.set_online = tape_3590_online,
- .freeze = tape_generic_pm_suspend,
.int_class = IRQIO_TAP,
};
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 380e6a67719c..a6d2a4792185 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -428,55 +428,6 @@ tape_cleanup_device(struct tape_device *device)
}
/*
- * Suspend device.
- *
- * Called by the common I/O layer if the drive should be suspended on user
- * request. We refuse to suspend if the device is loaded or in use for the
- * following reason:
- * While the Linux guest is suspended, it might be logged off which causes
- * devices to be detached. Tape devices are automatically rewound and unloaded
- * during DETACH processing (unless the tape device was attached with the
- * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to
- * resume the original state of the tape device, since we would need to
- * manually re-load the cartridge which was active at suspend time.
- */
-int tape_generic_pm_suspend(struct ccw_device *cdev)
-{
- struct tape_device *device;
-
- device = dev_get_drvdata(&cdev->dev);
- if (!device) {
- return -ENODEV;
- }
-
- DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n",
- device->cdev_id, device);
-
- if (device->medium_state != MS_UNLOADED) {
- pr_err("A cartridge is loaded in tape device %s, "
- "refusing to suspend\n", dev_name(&cdev->dev));
- return -EBUSY;
- }
-
- spin_lock_irq(get_ccwdev_lock(device->cdev));
- switch (device->tape_state) {
- case TS_INIT:
- case TS_NOT_OPER:
- case TS_UNUSED:
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
- break;
- default:
- pr_err("Tape device %s is busy, refusing to "
- "suspend\n", dev_name(&cdev->dev));
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
- return -EBUSY;
- }
-
- DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id);
- return 0;
-}
-
-/*
* Set device offline.
*
* Called by the common I/O layer if the drive should set offline on user
@@ -1360,7 +1311,6 @@ EXPORT_SYMBOL(tape_generic_remove);
EXPORT_SYMBOL(tape_generic_probe);
EXPORT_SYMBOL(tape_generic_online);
EXPORT_SYMBOL(tape_generic_offline);
-EXPORT_SYMBOL(tape_generic_pm_suspend);
EXPORT_SYMBOL(tape_put_device);
EXPORT_SYMBOL(tape_get_device);
EXPORT_SYMBOL(tape_state_verbose);
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index cbde65ab2170..1bbf27b98cf6 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -62,7 +62,6 @@ static int ur_probe(struct ccw_device *cdev);
static void ur_remove(struct ccw_device *cdev);
static int ur_set_online(struct ccw_device *cdev);
static int ur_set_offline(struct ccw_device *cdev);
-static int ur_pm_suspend(struct ccw_device *cdev);
static struct ccw_driver ur_driver = {
.driver = {
@@ -74,7 +73,6 @@ static struct ccw_driver ur_driver = {
.remove = ur_remove,
.set_online = ur_set_online,
.set_offline = ur_set_offline,
- .freeze = ur_pm_suspend,
.int_class = IRQIO_VMR,
};
@@ -165,28 +163,6 @@ static void urdev_put(struct urdev *urd)
}
/*
- * State and contents of ur devices can be changed by class D users issuing
- * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended.
- * Also the Linux guest might be logged off, which causes all active spool
- * files to be closed.
- * So we cannot guarantee that spool files are still the same when the Linux
- * guest is resumed. In order to avoid unpredictable results at resume time
- * we simply refuse to suspend if a ur device node is open.
- */
-static int ur_pm_suspend(struct ccw_device *cdev)
-{
- struct urdev *urd = dev_get_drvdata(&cdev->dev);
-
- TRACE("ur_pm_suspend: cdev=%p\n", cdev);
- if (urd->open_flag) {
- pr_err("Unit record device %s is busy, %s refusing to "
- "suspend.\n", dev_name(&cdev->dev), ur_banner);
- return -EBUSY;
- }
- return 0;
-}
-
-/*
* Low-level functions to do I/O to a ur device.
* alloc_chan_prog
* free_chan_prog
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 8f080d3fd380..c42405c620b5 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -120,31 +120,6 @@ static void chsc_subchannel_shutdown(struct subchannel *sch)
cio_disable_subchannel(sch);
}
-static int chsc_subchannel_prepare(struct subchannel *sch)
-{
- int cc;
- struct schib schib;
- /*
- * Don't allow suspend while the subchannel is not idle
- * since we don't have a way to clear the subchannel and
- * cannot disable it with a request running.
- */
- cc = stsch(sch->schid, &schib);
- if (!cc && scsw_stctl(&schib.scsw))
- return -EAGAIN;
- return 0;
-}
-
-static int chsc_subchannel_freeze(struct subchannel *sch)
-{
- return cio_disable_subchannel(sch);
-}
-
-static int chsc_subchannel_restore(struct subchannel *sch)
-{
- return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
-}
-
static struct css_device_id chsc_subchannel_ids[] = {
{ .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
{ /* end of list */ },
@@ -161,10 +136,6 @@ static struct css_driver chsc_subchannel_driver = {
.probe = chsc_subchannel_probe,
.remove = chsc_subchannel_remove,
.shutdown = chsc_subchannel_shutdown,
- .prepare = chsc_subchannel_prepare,
- .freeze = chsc_subchannel_freeze,
- .thaw = chsc_subchannel_restore,
- .restore = chsc_subchannel_restore,
};
static int __init chsc_init_dbfs(void)
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 72dd2471ec1e..b7b590646d58 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1109,11 +1109,6 @@ static ssize_t cmb_enable_store(struct device *dev,
}
DEVICE_ATTR_RW(cmb_enable);
-int ccw_set_cmf(struct ccw_device *cdev, int enable)
-{
- return cmbops->set(cdev, enable ? 2 : 0);
-}
-
/**
* enable_cmf() - switch on the channel measurement for a specific device
* @cdev: The ccw device to be enabled
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index cca1a7c4bb33..94c6470de635 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -18,7 +18,6 @@
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#include <linux/suspend.h>
#include <linux/proc_fs.h>
#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
@@ -1044,59 +1043,6 @@ static struct notifier_block css_reboot_notifier = {
.notifier_call = css_reboot_event,
};
-/*
- * Since the css devices are neither on a bus nor have a class
- * nor have a special device type, we cannot stop/restart channel
- * path measurements via the normal suspend/resume callbacks, but have
- * to use notifiers.
- */
-static int css_power_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- struct channel_subsystem *css;
- int ret;
-
- switch (event) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- ret = NOTIFY_DONE;
- for_each_css(css) {
- mutex_lock(&css->mutex);
- if (!css->cm_enabled) {
- mutex_unlock(&css->mutex);
- continue;
- }
- ret = __chsc_do_secm(css, 0);
- ret = notifier_from_errno(ret);
- mutex_unlock(&css->mutex);
- }
- break;
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- ret = NOTIFY_DONE;
- for_each_css(css) {
- mutex_lock(&css->mutex);
- if (!css->cm_enabled) {
- mutex_unlock(&css->mutex);
- continue;
- }
- ret = __chsc_do_secm(css, 1);
- ret = notifier_from_errno(ret);
- mutex_unlock(&css->mutex);
- }
- /* search for subchannels, which appeared during hibernation */
- css_schedule_reprobe();
- break;
- default:
- ret = NOTIFY_DONE;
- }
- return ret;
-
-}
-static struct notifier_block css_power_notifier = {
- .notifier_call = css_power_event,
-};
-
#define CIO_DMA_GFP (GFP_KERNEL | __GFP_ZERO)
static struct gen_pool *cio_dma_pool;
@@ -1242,12 +1188,9 @@ static int __init css_bus_init(void)
ret = register_reboot_notifier(&css_reboot_notifier);
if (ret)
goto out_unregister;
- ret = register_pm_notifier(&css_power_notifier);
- if (ret)
- goto out_unregister_rn;
ret = cio_dma_pool_init();
if (ret)
- goto out_unregister_pmn;
+ goto out_unregister_rn;
airq_init();
css_init_done = 1;
@@ -1255,8 +1198,6 @@ static int __init css_bus_init(void)
isc_register(IO_SCH_ISC);
return 0;
-out_unregister_pmn:
- unregister_pm_notifier(&css_power_notifier);
out_unregister_rn:
unregister_reboot_notifier(&css_reboot_notifier);
out_unregister:
@@ -1456,74 +1397,6 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
return ret;
}
-static int css_pm_prepare(struct device *dev)
-{
- struct subchannel *sch = to_subchannel(dev);
- struct css_driver *drv;
-
- if (mutex_is_locked(&sch->reg_mutex))
- return -EAGAIN;
- if (!sch->dev.driver)
- return 0;
- drv = to_cssdriver(sch->dev.driver);
- /* Notify drivers that they may not register children. */
- return drv->prepare ? drv->prepare(sch) : 0;
-}
-
-static void css_pm_complete(struct device *dev)
-{
- struct subchannel *sch = to_subchannel(dev);
- struct css_driver *drv;
-
- if (!sch->dev.driver)
- return;
- drv = to_cssdriver(sch->dev.driver);
- if (drv->complete)
- drv->complete(sch);
-}
-
-static int css_pm_freeze(struct device *dev)
-{
- struct subchannel *sch = to_subchannel(dev);
- struct css_driver *drv;
-
- if (!sch->dev.driver)
- return 0;
- drv = to_cssdriver(sch->dev.driver);
- return drv->freeze ? drv->freeze(sch) : 0;
-}
-
-static int css_pm_thaw(struct device *dev)
-{
- struct subchannel *sch = to_subchannel(dev);
- struct css_driver *drv;
-
- if (!sch->dev.driver)
- return 0;
- drv = to_cssdriver(sch->dev.driver);
- return drv->thaw ? drv->thaw(sch) : 0;
-}
-
-static int css_pm_restore(struct device *dev)
-{
- struct subchannel *sch = to_subchannel(dev);
- struct css_driver *drv;
-
- css_update_ssd_info(sch);
- if (!sch->dev.driver)
- return 0;
- drv = to_cssdriver(sch->dev.driver);
- return drv->restore ? drv->restore(sch) : 0;
-}
-
-static const struct dev_pm_ops css_pm_ops = {
- .prepare = css_pm_prepare,
- .complete = css_pm_complete,
- .freeze = css_pm_freeze,
- .thaw = css_pm_thaw,
- .restore = css_pm_restore,
-};
-
static struct bus_type css_bus_type = {
.name = "css",
.match = css_bus_match,
@@ -1531,7 +1404,6 @@ static struct bus_type css_bus_type = {
.remove = css_remove,
.shutdown = css_shutdown,
.uevent = css_uevent,
- .pm = &css_pm_ops,
};
/**
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 3f322ea0f498..2eddfc47f687 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -72,11 +72,6 @@ struct chp_link;
* @probe: function called on probe
* @remove: function called on remove
* @shutdown: called at device shutdown
- * @prepare: prepare for pm state transition
- * @complete: undo work done in @prepare
- * @freeze: callback for freezing during hibernation snapshotting
- * @thaw: undo work done in @freeze
- * @restore: callback for restoring after hibernation
* @settle: wait for asynchronous work to finish
*/
struct css_driver {
@@ -88,11 +83,6 @@ struct css_driver {
int (*probe)(struct subchannel *);
int (*remove)(struct subchannel *);
void (*shutdown)(struct subchannel *);
- int (*prepare) (struct subchannel *);
- void (*complete) (struct subchannel *);
- int (*freeze)(struct subchannel *);
- int (*thaw) (struct subchannel *);
- int (*restore)(struct subchannel *);
int (*settle)(void);
};
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index b29fe8d50baf..e0005a4fc978 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -149,19 +149,6 @@ static struct css_device_id io_subchannel_ids[] = {
{ /* end of list */ },
};
-static int io_subchannel_prepare(struct subchannel *sch)
-{
- struct ccw_device *cdev;
- /*
- * Don't allow suspend while a ccw device registration
- * is still outstanding.
- */
- cdev = sch_get_cdev(sch);
- if (cdev && !device_is_registered(&cdev->dev))
- return -EAGAIN;
- return 0;
-}
-
static int io_subchannel_settle(void)
{
int ret;
@@ -186,7 +173,6 @@ static struct css_driver io_subchannel_driver = {
.probe = io_subchannel_probe,
.remove = io_subchannel_remove,
.shutdown = io_subchannel_shutdown,
- .prepare = io_subchannel_prepare,
.settle = io_subchannel_settle,
};
@@ -1422,7 +1408,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
}
if (device_is_disconnected(cdev))
return IO_SCH_REPROBE;
- if (cdev->online && !cdev->private->flags.resuming)
+ if (cdev->online)
return IO_SCH_VERIFY;
if (cdev->private->state == DEV_STATE_NOT_OPER)
return IO_SCH_UNREG_ATTACH;
@@ -1514,11 +1500,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
break;
case IO_SCH_UNREG_ATTACH:
spin_lock_irqsave(sch->lock, flags);
- if (cdev->private->flags.resuming) {
- /* Device will be handled later. */
- rc = 0;
- goto out_unlock;
- }
sch_set_cdev(sch, NULL);
spin_unlock_irqrestore(sch->lock, flags);
/* Unregister ccw device. */
@@ -1531,7 +1512,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
switch (action) {
case IO_SCH_ORPH_UNREG:
case IO_SCH_UNREG:
- if (!cdev || !cdev->private->flags.resuming)
+ if (!cdev)
css_sch_device_unregister(sch);
break;
case IO_SCH_ORPH_ATTACH:
@@ -1664,10 +1645,10 @@ void __init ccw_device_destroy_console(struct ccw_device *cdev)
struct io_subchannel_private *io_priv = to_io_private(sch);
set_io_private(sch, NULL);
- put_device(&sch->dev);
- put_device(&cdev->dev);
dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area),
io_priv->dma_area, io_priv->dma_area_dma);
+ put_device(&sch->dev);
+ put_device(&cdev->dev);
kfree(io_priv);
}
@@ -1690,14 +1671,6 @@ void ccw_device_wait_idle(struct ccw_device *cdev)
udelay_simple(100);
}
}
-
-static int ccw_device_pm_restore(struct device *dev);
-
-int ccw_device_force_console(struct ccw_device *cdev)
-{
- return ccw_device_pm_restore(&cdev->dev);
-}
-EXPORT_SYMBOL_GPL(ccw_device_force_console);
#endif
/**
@@ -1798,235 +1771,6 @@ static void ccw_device_shutdown(struct device *dev)
__disable_cmf(cdev);
}
-static int ccw_device_pm_prepare(struct device *dev)
-{
- struct ccw_device *cdev = to_ccwdev(dev);
-
- if (work_pending(&cdev->private->todo_work))
- return -EAGAIN;
- /* Fail while device is being set online/offline. */
- if (atomic_read(&cdev->private->onoff))
- return -EAGAIN;
-
- if (cdev->online && cdev->drv && cdev->drv->prepare)
- return cdev->drv->prepare(cdev);
-
- return 0;
-}
-
-static void ccw_device_pm_complete(struct device *dev)
-{
- struct ccw_device *cdev = to_ccwdev(dev);
-
- if (cdev->online && cdev->drv && cdev->drv->complete)
- cdev->drv->complete(cdev);
-}
-
-static int ccw_device_pm_freeze(struct device *dev)
-{
- struct ccw_device *cdev = to_ccwdev(dev);
- struct subchannel *sch = to_subchannel(cdev->dev.parent);
- int ret, cm_enabled;
-
- /* Fail suspend while device is in transistional state. */
- if (!dev_fsm_final_state(cdev))
- return -EAGAIN;
- if (!cdev->online)
- return 0;
- if (cdev->drv && cdev->drv->freeze) {
- ret = cdev->drv->freeze(cdev);
- if (ret)
- return ret;
- }
-
- spin_lock_irq(sch->lock);
- cm_enabled = cdev->private->cmb != NULL;
- spin_unlock_irq(sch->lock);
- if (cm_enabled) {
- /* Don't have the css write on memory. */
- ret = ccw_set_cmf(cdev, 0);
- if (ret)
- return ret;
- }
- /* From here on, disallow device driver I/O. */
- spin_lock_irq(sch->lock);
- ret = cio_disable_subchannel(sch);
- spin_unlock_irq(sch->lock);
-
- return ret;
-}
-
-static int ccw_device_pm_thaw(struct device *dev)
-{
- struct ccw_device *cdev = to_ccwdev(dev);
- struct subchannel *sch = to_subchannel(cdev->dev.parent);
- int ret, cm_enabled;
-
- if (!cdev->online)
- return 0;
-
- spin_lock_irq(sch->lock);
- /* Allow device driver I/O again. */
- ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
- cm_enabled = cdev->private->cmb != NULL;
- spin_unlock_irq(sch->lock);
- if (ret)
- return ret;
-
- if (cm_enabled) {
- ret = ccw_set_cmf(cdev, 1);
- if (ret)
- return ret;
- }
-
- if (cdev->drv && cdev->drv->thaw)
- ret = cdev->drv->thaw(cdev);
-
- return ret;
-}
-
-static void __ccw_device_pm_restore(struct ccw_device *cdev)
-{
- struct subchannel *sch = to_subchannel(cdev->dev.parent);
-
- spin_lock_irq(sch->lock);
- if (cio_is_console(sch->schid)) {
- cio_enable_subchannel(sch, (u32)(addr_t)sch);
- goto out_unlock;
- }
- /*
- * While we were sleeping, devices may have gone or become
- * available again. Kick re-detection.
- */
- cdev->private->flags.resuming = 1;
- cdev->private->path_new_mask = LPM_ANYPATH;
- css_sched_sch_todo(sch, SCH_TODO_EVAL);
- spin_unlock_irq(sch->lock);
- css_wait_for_slow_path();
-
- /* cdev may have been moved to a different subchannel. */
- sch = to_subchannel(cdev->dev.parent);
- spin_lock_irq(sch->lock);
- if (cdev->private->state != DEV_STATE_ONLINE &&
- cdev->private->state != DEV_STATE_OFFLINE)
- goto out_unlock;
-
- ccw_device_recognition(cdev);
- spin_unlock_irq(sch->lock);
- wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
- cdev->private->state == DEV_STATE_DISCONNECTED);
- spin_lock_irq(sch->lock);
-
-out_unlock:
- cdev->private->flags.resuming = 0;
- spin_unlock_irq(sch->lock);
-}
-
-static int resume_handle_boxed(struct ccw_device *cdev)
-{
- cdev->private->state = DEV_STATE_BOXED;
- if (ccw_device_notify(cdev, CIO_BOXED) == NOTIFY_OK)
- return 0;
- ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
- return -ENODEV;
-}
-
-static int resume_handle_disc(struct ccw_device *cdev)
-{
- cdev->private->state = DEV_STATE_DISCONNECTED;
- if (ccw_device_notify(cdev, CIO_GONE) == NOTIFY_OK)
- return 0;
- ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
- return -ENODEV;
-}
-
-static int ccw_device_pm_restore(struct device *dev)
-{
- struct ccw_device *cdev = to_ccwdev(dev);
- struct subchannel *sch;
- int ret = 0;
-
- __ccw_device_pm_restore(cdev);
- sch = to_subchannel(cdev->dev.parent);
- spin_lock_irq(sch->lock);
- if (cio_is_console(sch->schid))
- goto out_restore;
-
- /* check recognition results */
- switch (cdev->private->state) {
- case DEV_STATE_OFFLINE:
- case DEV_STATE_ONLINE:
- cdev->private->flags.donotify = 0;
- break;
- case DEV_STATE_BOXED:
- ret = resume_handle_boxed(cdev);
- if (ret)
- goto out_unlock;
- goto out_restore;
- default:
- ret = resume_handle_disc(cdev);
- if (ret)
- goto out_unlock;
- goto out_restore;
- }
- /* check if the device type has changed */
- if (!ccw_device_test_sense_data(cdev)) {
- ccw_device_update_sense_data(cdev);
- ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
- ret = -ENODEV;
- goto out_unlock;
- }
- if (!cdev->online)
- goto out_unlock;
-
- if (ccw_device_online(cdev)) {
- ret = resume_handle_disc(cdev);
- if (ret)
- goto out_unlock;
- goto out_restore;
- }
- spin_unlock_irq(sch->lock);
- wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
- spin_lock_irq(sch->lock);
-
- if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_BAD) {
- ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
- ret = -ENODEV;
- goto out_unlock;
- }
-
- /* reenable cmf, if needed */
- if (cdev->private->cmb) {
- spin_unlock_irq(sch->lock);
- ret = ccw_set_cmf(cdev, 1);
- spin_lock_irq(sch->lock);
- if (ret) {
- CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed "
- "(rc=%d)\n", cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno, ret);
- ret = 0;
- }
- }
-
-out_restore:
- spin_unlock_irq(sch->lock);
- if (cdev->online && cdev->drv && cdev->drv->restore)
- ret = cdev->drv->restore(cdev);
- return ret;
-
-out_unlock:
- spin_unlock_irq(sch->lock);
- return ret;
-}
-
-static const struct dev_pm_ops ccw_pm_ops = {
- .prepare = ccw_device_pm_prepare,
- .complete = ccw_device_pm_complete,
- .freeze = ccw_device_pm_freeze,
- .thaw = ccw_device_pm_thaw,
- .restore = ccw_device_pm_restore,
-};
-
static struct bus_type ccw_bus_type = {
.name = "ccw",
.match = ccw_bus_match,
@@ -2034,7 +1778,6 @@ static struct bus_type ccw_bus_type = {
.probe = ccw_device_probe,
.remove = ccw_device_remove,
.shutdown = ccw_device_shutdown,
- .pm = &ccw_pm_ops,
};
/**
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 853b6a8ca095..24b2fce69590 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -143,6 +143,5 @@ void retry_set_schib(struct ccw_device *cdev);
void cmf_retry_copy_block(struct ccw_device *);
int cmf_reenable(struct ccw_device *);
void cmf_reactivate(void);
-int ccw_set_cmf(struct ccw_device *cdev, int enable);
extern struct device_attribute dev_attr_cmb_enable;
#endif
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 8fc267324ebb..6420b197bb05 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -224,12 +224,6 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
wake_up(&cdev->private->wait_q);
return;
}
- if (cdev->private->flags.resuming) {
- cdev->private->state = state;
- cdev->private->flags.recog_done = 1;
- wake_up(&cdev->private->wait_q);
- return;
- }
switch (state) {
case DEV_STATE_NOT_OPER:
break;
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c
index 53468ae64b99..c8964e0a23e7 100644
--- a/drivers/s390/cio/eadm_sch.c
+++ b/drivers/s390/cio/eadm_sch.c
@@ -306,16 +306,6 @@ static void eadm_subchannel_shutdown(struct subchannel *sch)
eadm_quiesce(sch);
}
-static int eadm_subchannel_freeze(struct subchannel *sch)
-{
- return cio_disable_subchannel(sch);
-}
-
-static int eadm_subchannel_restore(struct subchannel *sch)
-{
- return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
-}
-
/**
* eadm_subchannel_sch_event - process subchannel event
* @sch: subchannel
@@ -369,9 +359,6 @@ static struct css_driver eadm_subchannel_driver = {
.remove = eadm_subchannel_remove,
.shutdown = eadm_subchannel_shutdown,
.sch_event = eadm_subchannel_sch_event,
- .freeze = eadm_subchannel_freeze,
- .thaw = eadm_subchannel_restore,
- .restore = eadm_subchannel_restore,
};
static int __init eadm_sch_init(void)
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index c03b4a19974e..85a11c1836e5 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -160,7 +160,6 @@ struct ccw_device_private {
unsigned int donotify:1; /* call notify function */
unsigned int recog_done:1; /* dev. recog. complete */
unsigned int fake_irb:2; /* deliver faked irb */
- unsigned int resuming:1; /* recognition while resume */
unsigned int pgroup:1; /* pathgroup is set up */
unsigned int mpath:1; /* multipathing is set up */
unsigned int pgid_unknown:1;/* unknown pgid state */
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index ef738b42a092..2758d05a802d 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright IBM Corp. 2006, 2012
+ * Copyright IBM Corp. 2006, 2020
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
* Felix Beck <felix.beck@de.ibm.com>
* Holger Dengler <hd@linux.vnet.ibm.com>
+ * Harald Freudenberger <freude@linux.ibm.com>
*
* Adjunct processor bus.
*/
@@ -73,6 +74,12 @@ EXPORT_SYMBOL(ap_perms);
DEFINE_MUTEX(ap_perms_mutex);
EXPORT_SYMBOL(ap_perms_mutex);
+/* # of bus scans since init */
+static atomic64_t ap_scan_bus_count;
+
+/* completion for initial APQN bindings complete */
+static DECLARE_COMPLETION(ap_init_apqn_bindings_complete);
+
static struct ap_config_info *ap_qci_info;
/*
@@ -577,23 +584,125 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
*/
static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)
{
+ int rc;
struct ap_device *ap_dev = to_ap_dev(dev);
- int retval = 0;
- if (!ap_dev)
- return -ENODEV;
+ /* Uevents from ap bus core don't need extensions to the env */
+ if (dev == ap_root_device)
+ return 0;
/* Set up DEV_TYPE environment variable. */
- retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
- if (retval)
- return retval;
+ rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
+ if (rc)
+ return rc;
/* Add MODALIAS= */
- retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
+ rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static void ap_send_init_scan_done_uevent(void)
+{
+ char *envp[] = { "INITSCAN=done", NULL };
- return retval;
+ kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp);
}
+static void ap_send_bindings_complete_uevent(void)
+{
+ char *envp[] = { "BINDINGS=complete", NULL };
+
+ kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp);
+}
+
+/*
+ * calc # of bound APQNs
+ */
+
+struct __ap_calc_ctrs {
+ unsigned int apqns;
+ unsigned int bound;
+};
+
+static int __ap_calc_helper(struct device *dev, void *arg)
+{
+ struct __ap_calc_ctrs *pctrs = (struct __ap_calc_ctrs *) arg;
+
+ if (is_queue_dev(dev)) {
+ pctrs->apqns++;
+ if ((to_ap_dev(dev))->drv)
+ pctrs->bound++;
+ }
+
+ return 0;
+}
+
+static void ap_calc_bound_apqns(unsigned int *apqns, unsigned int *bound)
+{
+ struct __ap_calc_ctrs ctrs;
+
+ memset(&ctrs, 0, sizeof(ctrs));
+ bus_for_each_dev(&ap_bus_type, NULL, (void *) &ctrs, __ap_calc_helper);
+
+ *apqns = ctrs.apqns;
+ *bound = ctrs.bound;
+}
+
+/*
+ * After initial ap bus scan do check if all existing APQNs are
+ * bound to device drivers.
+ */
+static void ap_check_bindings_complete(void)
+{
+ unsigned int apqns, bound;
+
+ if (atomic64_read(&ap_scan_bus_count) >= 1) {
+ ap_calc_bound_apqns(&apqns, &bound);
+ if (bound == apqns) {
+ if (!completion_done(&ap_init_apqn_bindings_complete)) {
+ complete_all(&ap_init_apqn_bindings_complete);
+ AP_DBF(DBF_INFO, "%s complete\n", __func__);
+ }
+ ap_send_bindings_complete_uevent();
+ }
+ }
+}
+
+/*
+ * Interface to wait for the AP bus to have done one initial ap bus
+ * scan and all detected APQNs have been bound to device drivers.
+ * If these both conditions are not fulfilled, this function blocks
+ * on a condition with wait_for_completion_interruptible_timeout().
+ * If these both conditions are fulfilled (before the timeout hits)
+ * the return value is 0. If the timeout (in jiffies) hits instead
+ * -ETIME is returned. On failures negative return values are
+ * returned to the caller.
+ */
+int ap_wait_init_apqn_bindings_complete(unsigned long timeout)
+{
+ long l;
+
+ if (completion_done(&ap_init_apqn_bindings_complete))
+ return 0;
+
+ if (timeout)
+ l = wait_for_completion_interruptible_timeout(
+ &ap_init_apqn_bindings_complete, timeout);
+ else
+ l = wait_for_completion_interruptible(
+ &ap_init_apqn_bindings_complete);
+ if (l < 0)
+ return l == -ERESTARTSYS ? -EINTR : l;
+ else if (l == 0 && timeout)
+ return -ETIME;
+
+ return 0;
+}
+EXPORT_SYMBOL(ap_wait_init_apqn_bindings_complete);
+
static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data)
{
if (is_queue_dev(dev) &&
@@ -602,12 +711,6 @@ static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data)
return 0;
}
-static struct bus_type ap_bus_type = {
- .name = "ap",
- .match = &ap_bus_match,
- .uevent = &ap_uevent,
-};
-
static int __ap_revise_reserved(struct device *dev, void *dummy)
{
int rc, card, queue, devres, drvres;
@@ -719,7 +822,8 @@ static int ap_device_probe(struct device *dev)
hash_del(&to_ap_queue(dev)->hnode);
spin_unlock_bh(&ap_queues_lock);
ap_dev->drv = NULL;
- }
+ } else
+ ap_check_bindings_complete();
out:
if (rc)
@@ -749,6 +853,7 @@ static int ap_device_remove(struct device *dev)
if (is_queue_dev(dev))
hash_del(&to_ap_queue(dev)->hnode);
spin_unlock_bh(&ap_queues_lock);
+ ap_dev->drv = NULL;
put_device(dev);
@@ -1166,21 +1271,55 @@ static ssize_t aqmask_store(struct bus_type *bus, const char *buf,
static BUS_ATTR_RW(aqmask);
-static struct bus_attribute *const ap_bus_attrs[] = {
- &bus_attr_ap_domain,
- &bus_attr_ap_control_domain_mask,
- &bus_attr_ap_usage_domain_mask,
- &bus_attr_ap_adapter_mask,
- &bus_attr_config_time,
- &bus_attr_poll_thread,
- &bus_attr_ap_interrupts,
- &bus_attr_poll_timeout,
- &bus_attr_ap_max_domain_id,
- &bus_attr_ap_max_adapter_id,
- &bus_attr_apmask,
- &bus_attr_aqmask,
+static ssize_t scans_show(struct bus_type *bus, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
+ atomic64_read(&ap_scan_bus_count));
+}
+
+static BUS_ATTR_RO(scans);
+
+static ssize_t bindings_show(struct bus_type *bus, char *buf)
+{
+ int rc;
+ unsigned int apqns, n;
+
+ ap_calc_bound_apqns(&apqns, &n);
+ if (atomic64_read(&ap_scan_bus_count) >= 1 && n == apqns)
+ rc = scnprintf(buf, PAGE_SIZE, "%u/%u (complete)\n", n, apqns);
+ else
+ rc = scnprintf(buf, PAGE_SIZE, "%u/%u\n", n, apqns);
+
+ return rc;
+}
+
+static BUS_ATTR_RO(bindings);
+
+static struct attribute *ap_bus_attrs[] = {
+ &bus_attr_ap_domain.attr,
+ &bus_attr_ap_control_domain_mask.attr,
+ &bus_attr_ap_usage_domain_mask.attr,
+ &bus_attr_ap_adapter_mask.attr,
+ &bus_attr_config_time.attr,
+ &bus_attr_poll_thread.attr,
+ &bus_attr_ap_interrupts.attr,
+ &bus_attr_poll_timeout.attr,
+ &bus_attr_ap_max_domain_id.attr,
+ &bus_attr_ap_max_adapter_id.attr,
+ &bus_attr_apmask.attr,
+ &bus_attr_aqmask.attr,
+ &bus_attr_scans.attr,
+ &bus_attr_bindings.attr,
NULL,
};
+ATTRIBUTE_GROUPS(ap_bus);
+
+static struct bus_type ap_bus_type = {
+ .name = "ap",
+ .bus_groups = ap_bus_groups,
+ .match = &ap_bus_match,
+ .uevent = &ap_uevent,
+};
/**
* ap_select_domain(): Select an AP domain if possible and we haven't
@@ -1608,6 +1747,12 @@ static void ap_scan_bus(struct work_struct *unused)
ap_domain_index);
}
+ if (atomic64_inc_return(&ap_scan_bus_count) == 1) {
+ AP_DBF(DBF_DEBUG, "%s init scan complete\n", __func__);
+ ap_send_init_scan_done_uevent();
+ ap_check_bindings_complete();
+ }
+
mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
}
@@ -1655,7 +1800,7 @@ static void __init ap_perms_init(void)
*/
static int __init ap_module_init(void)
{
- int rc, i;
+ int rc;
rc = ap_debug_init();
if (rc)
@@ -1694,17 +1839,13 @@ static int __init ap_module_init(void)
rc = bus_register(&ap_bus_type);
if (rc)
goto out;
- for (i = 0; ap_bus_attrs[i]; i++) {
- rc = bus_create_file(&ap_bus_type, ap_bus_attrs[i]);
- if (rc)
- goto out_bus;
- }
/* Create /sys/devices/ap. */
ap_root_device = root_device_register("ap");
rc = PTR_ERR_OR_ZERO(ap_root_device);
if (rc)
goto out_bus;
+ ap_root_device->bus = &ap_bus_type;
/* Setup the AP bus rescan timer. */
timer_setup(&ap_config_timer, ap_config_timeout, 0);
@@ -1733,8 +1874,6 @@ out_work:
hrtimer_cancel(&ap_poll_timer);
root_device_unregister(ap_root_device);
out_bus:
- while (i--)
- bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
bus_unregister(&ap_bus_type);
out:
if (ap_using_interrupts())
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 5029b80132aa..472efd3a755c 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -350,4 +350,16 @@ int ap_parse_mask_str(const char *str,
unsigned long *bitmap, int bits,
struct mutex *lock);
+/*
+ * Interface to wait for the AP bus to have done one initial ap bus
+ * scan and all detected APQNs have been bound to device drivers.
+ * If these both conditions are not fulfilled, this function blocks
+ * on a condition with wait_for_completion_killable_timeout().
+ * If these both conditions are fulfilled (before the timeout hits)
+ * the return value is 0. If the timeout (in jiffies) hits instead
+ * -ETIME is returned. On failures negative return values are
+ * returned to the caller.
+ */
+int ap_wait_init_apqn_bindings_complete(unsigned long timeout);
+
#endif /* _AP_BUS_H_ */
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index dd84995049b9..cf23ce1b1146 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -150,6 +150,8 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey)
u16 cardnr, domain;
struct keytoken_header *hdr = (struct keytoken_header *)key;
+ zcrypt_wait_api_operational();
+
/*
* The cca_xxx2protkey call may fail when a card has been
* addressed where the master key was changed after last fetch
@@ -197,6 +199,8 @@ static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
u16 card, dom;
u32 nr_apqns, *apqns = NULL;
+ zcrypt_wait_api_operational();
+
/* build a list of apqns suitable for ep11 keys with cpacf support */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
ZCRYPT_CEX7, EP11_API_V, NULL);
@@ -230,6 +234,8 @@ static int pkey_ep11key2pkey(const u8 *key, struct pkey_protkey *pkey)
u32 nr_apqns, *apqns = NULL;
struct ep11keyblob *kb = (struct ep11keyblob *) key;
+ zcrypt_wait_api_operational();
+
/* build a list of apqns suitable for this key */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
@@ -436,6 +442,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
if (rc == 0)
break;
/* PCKMO failed, so try the CCA secure key way */
+ zcrypt_wait_api_operational();
rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype,
ckey.clrkey, tmpbuf);
if (rc == 0)
@@ -625,6 +632,8 @@ static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
return -EINVAL;
}
+ zcrypt_wait_api_operational();
+
/* simple try all apqns from the list */
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
@@ -801,6 +810,8 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
return -EINVAL;
}
+ zcrypt_wait_api_operational();
+
/* simple try all apqns from the list */
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
@@ -838,6 +849,8 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
if (keylen < sizeof(struct keytoken_header) || flags == 0)
return -EINVAL;
+ zcrypt_wait_api_operational();
+
if (hdr->type == TOKTYPE_NON_CCA
&& (hdr->version == TOKVER_EP11_AES_WITH_HEADER
|| hdr->version == TOKVER_EP11_ECC_WITH_HEADER)
@@ -941,6 +954,8 @@ static int pkey_apqns4keytype(enum pkey_key_type ktype,
int rc;
u32 _nr_apqns, *_apqns = NULL;
+ zcrypt_wait_api_operational();
+
if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {
u64 cur_mkvp = 0, old_mkvp = 0;
int minhwtype = ZCRYPT_CEX3C;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index f60f9fb25214..10206e4498d0 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1992,6 +1992,72 @@ void zcrypt_rng_device_remove(void)
mutex_unlock(&zcrypt_rng_mutex);
}
+/*
+ * Wait until the zcrypt api is operational.
+ * The AP bus scan and the binding of ap devices to device drivers is
+ * an asynchronous job. This function waits until these initial jobs
+ * are done and so the zcrypt api should be ready to serve crypto
+ * requests - if there are resources available. The function uses an
+ * internal timeout of 60s. The very first caller will either wait for
+ * ap bus bindings complete or the timeout happens. This state will be
+ * remembered for further callers which will only be blocked until a
+ * decision is made (timeout or bindings complete).
+ * On timeout -ETIME is returned, on success the return value is 0.
+ */
+int zcrypt_wait_api_operational(void)
+{
+ static DEFINE_MUTEX(zcrypt_wait_api_lock);
+ static int zcrypt_wait_api_state;
+ int rc;
+
+ rc = mutex_lock_interruptible(&zcrypt_wait_api_lock);
+ if (rc)
+ return rc;
+
+ switch (zcrypt_wait_api_state) {
+ case 0:
+ /* initial state, invoke wait for the ap bus complete */
+ rc = ap_wait_init_apqn_bindings_complete(
+ msecs_to_jiffies(60 * 1000));
+ switch (rc) {
+ case 0:
+ /* ap bus bindings are complete */
+ zcrypt_wait_api_state = 1;
+ break;
+ case -EINTR:
+ /* interrupted, go back to caller */
+ break;
+ case -ETIME:
+ /* timeout */
+ ZCRYPT_DBF(DBF_WARN,
+ "%s ap_wait_init_apqn_bindings_complete() returned with ETIME\n",
+ __func__);
+ zcrypt_wait_api_state = -ETIME;
+ break;
+ default:
+ /* other failure */
+ ZCRYPT_DBF(DBF_DEBUG,
+ "%s ap_wait_init_apqn_bindings_complete() failure rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ break;
+ case 1:
+ /* a previous caller already found ap bus bindings complete */
+ rc = 0;
+ break;
+ default:
+ /* a previous caller had timeout or other failure */
+ rc = zcrypt_wait_api_state;
+ break;
+ }
+
+ mutex_unlock(&zcrypt_wait_api_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(zcrypt_wait_api_operational);
+
int __init zcrypt_debug_init(void)
{
zcrypt_dbf_info = debug_register("zcrypt", 1, 1,
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 51c0b8bdef50..16219efb2f61 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -162,6 +162,8 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus);
int zcrypt_device_status_ext(int card, int queue,
struct zcrypt_device_status_ext *devstatus);
+int zcrypt_wait_api_operational(void);
+
static inline unsigned long z_copy_from_user(bool userspace,
void *to,
const void __user *from,
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index d9fd0a41da64..bdf2cc1ea713 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -194,23 +194,21 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)
}
/**
- * zfcp_ccw_offline_sync - shut down adapter and wait for it to finish
+ * zfcp_ccw_set_offline - set_offline function of zfcp driver
* @cdev: pointer to belonging ccw device
- * @set: Status flags to set.
- * @tag: s390dbf trace record tag
*
* This function gets called by the common i/o layer and sets an adapter
* into state offline.
*/
-static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag)
+static int zfcp_ccw_set_offline(struct ccw_device *cdev)
{
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
if (!adapter)
return 0;
- zfcp_erp_set_adapter_status(adapter, set);
- zfcp_erp_adapter_shutdown(adapter, 0, tag);
+ zfcp_erp_set_adapter_status(adapter, 0);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1");
zfcp_erp_wait(adapter);
zfcp_ccw_adapter_put(adapter);
@@ -218,18 +216,6 @@ static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag)
}
/**
- * zfcp_ccw_set_offline - set_offline function of zfcp driver
- * @cdev: pointer to belonging ccw device
- *
- * This function gets called by the common i/o layer and sets an adapter
- * into state offline.
- */
-static int zfcp_ccw_set_offline(struct ccw_device *cdev)
-{
- return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1");
-}
-
-/**
* zfcp_ccw_notify - ccw notify function
* @cdev: pointer to belonging ccw device
* @event: indicates if adapter was detached or attached
@@ -246,11 +232,6 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
switch (event) {
case CIO_GONE:
- if (atomic_read(&adapter->status) &
- ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */
- zfcp_dbf_hba_basic("ccnigo1", adapter);
- break;
- }
dev_warn(&cdev->dev, "The FCP device has been detached\n");
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1");
break;
@@ -260,11 +241,6 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2");
break;
case CIO_OPER:
- if (atomic_read(&adapter->status) &
- ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */
- zfcp_dbf_hba_basic("ccniop1", adapter);
- break;
- }
dev_info(&cdev->dev, "The FCP device is operational again\n");
zfcp_erp_set_adapter_status(adapter,
ZFCP_STATUS_COMMON_RUNNING);
@@ -300,28 +276,6 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
zfcp_ccw_adapter_put(adapter);
}
-static int zfcp_ccw_suspend(struct ccw_device *cdev)
-{
- zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1");
- return 0;
-}
-
-static int zfcp_ccw_thaw(struct ccw_device *cdev)
-{
- /* trace records for thaw and final shutdown during suspend
- can only be found in system dump until the end of suspend
- but not after resume because it's based on the memory image
- right after the very first suspend (freeze) callback */
- zfcp_ccw_activate(cdev, 0, "ccthaw1");
- return 0;
-}
-
-static int zfcp_ccw_resume(struct ccw_device *cdev)
-{
- zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1");
- return 0;
-}
-
struct ccw_driver zfcp_ccw_driver = {
.driver = {
.owner = THIS_MODULE,
@@ -334,7 +288,4 @@ struct ccw_driver zfcp_ccw_driver = {
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
.shutdown = zfcp_ccw_shutdown,
- .freeze = zfcp_ccw_suspend,
- .thaw = zfcp_ccw_thaw,
- .restore = zfcp_ccw_resume,
};
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 673e42defb91..ca473b368905 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -263,31 +263,6 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount,
spin_unlock_irqrestore(&dbf->pay_lock, flags);
}
-/**
- * zfcp_dbf_hba_basic - trace event for basic adapter events
- * @tag: identifier for event
- * @adapter: pointer to struct zfcp_adapter
- */
-void zfcp_dbf_hba_basic(char *tag, struct zfcp_adapter *adapter)
-{
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_hba *rec = &dbf->hba_buf;
- static int const level = 1;
- unsigned long flags;
-
- if (unlikely(!debug_level_enabled(dbf->hba, level)))
- return;
-
- spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(rec, 0, sizeof(*rec));
-
- memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
- rec->id = ZFCP_DBF_HBA_BASIC;
-
- debug_event(dbf->hba, level, rec, sizeof(*rec));
- spin_unlock_irqrestore(&dbf->hba_lock, flags);
-}
-
static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
struct zfcp_adapter *adapter,
struct zfcp_port *port,
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index da8a5ceb615c..5069b555c6c1 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -70,7 +70,6 @@
#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
#define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010
-#define ZFCP_STATUS_ADAPTER_SUSPENDED 0x00000040
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 3ef5d74331c3..fdac6350c579 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -49,7 +49,6 @@ extern void zfcp_dbf_hba_fsf_fces(char *tag, const struct zfcp_fsf_req *req,
u32 fc_security_new);
extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
-extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *);
extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);