summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-15 03:22:26 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-15 03:22:26 +0300
commit586592478b1fa8bb8cd6875a9191468e9b1a8b13 (patch)
treeb93ea8074b11ffa3c10ec4c0ed910479a6564bb0 /drivers/s390
parent0b03beface02d519693edb8020f9811c67d5c88f (diff)
parent343dbdb7cb8997a2cb0fd804d6563b8a6de8d49b (diff)
downloadlinux-586592478b1fa8bb8cd6875a9191468e9b1a8b13.tar.xz
Merge tag 's390-5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Heiko Carstens: - Add support for the hugetlb_cma command line option to allocate gigantic hugepages using CMA - Add arch_get_random_long() support. - Add ap bus userspace notifications. - Increase default size of vmalloc area to 512GB and otherwise let it increase dynamically by the size of physical memory. This should fix all occurrences where the vmalloc area was not large enough. - Completely get rid of set_fs() (aka select SET_FS) and rework address space handling while doing that; making address space handling much more simple. - Reimplement getcpu vdso syscall in C. - Add support for extended SCLP responses (> 4k). This allows e.g. to handle also potential large system configurations. - Simplify KASAN by removing 3-level page table support and only supporting 4-levels from now on. - Improve debug-ability of the kernel decompressor code, which now prints also stack traces and symbols in case of problems to the console. - Remove more power management leftovers. - Other various fixes and improvements all over the place. * tag 's390-5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (62 commits) s390/mm: add support to allocate gigantic hugepages using CMA s390/crypto: add arch_get_random_long() support s390/smp: perform initial CPU reset also for SMT siblings s390/mm: use invalid asce for user space when switching to init_mm s390/idle: fix accounting with machine checks s390/idle: add missing mt_cycles calculation s390/boot: add build-id to decompressor s390/kexec_file: fix diag308 subcode when loading crash kernel s390/cio: fix use-after-free in ccw_device_destroy_console s390/cio: remove pm support from ccw bus driver s390/cio: remove pm support from css-bus driver s390/cio: remove pm support from IO subchannel drivers s390/cio: remove pm support from chsc subchannel driver s390/vmur: remove unused pm related functions s390/tape: remove unsupported PM functions s390/cio: remove pm support from eadm-sch drivers s390: remove pm support from console drivers s390/dasd: remove unused pm related functions s390/zfcp: remove pm support from zfcp driver s390/ap: let bus_register() add the AP bus sysfs attributes ...
Diffstat (limited to 'drivers/s390')
-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
35 files changed, 355 insertions, 1037 deletions
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 *);