162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright IBM Corp. 2001, 2018
462306a36Sopenharmony_ci *  Author(s): Robert Burroughs
562306a36Sopenharmony_ci *	       Eric Rossman (edrossma@us.ibm.com)
662306a36Sopenharmony_ci *	       Cornelia Huck <cornelia.huck@de.ibm.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
962306a36Sopenharmony_ci *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
1062306a36Sopenharmony_ci *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
1162306a36Sopenharmony_ci *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
1262306a36Sopenharmony_ci *  Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com>
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/miscdevice.h>
1962306a36Sopenharmony_ci#include <linux/fs.h>
2062306a36Sopenharmony_ci#include <linux/compat.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/atomic.h>
2362306a36Sopenharmony_ci#include <linux/uaccess.h>
2462306a36Sopenharmony_ci#include <linux/hw_random.h>
2562306a36Sopenharmony_ci#include <linux/debugfs.h>
2662306a36Sopenharmony_ci#include <linux/cdev.h>
2762306a36Sopenharmony_ci#include <linux/ctype.h>
2862306a36Sopenharmony_ci#include <linux/capability.h>
2962306a36Sopenharmony_ci#include <asm/debug.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
3262306a36Sopenharmony_ci#include <asm/trace/zcrypt.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "zcrypt_api.h"
3562306a36Sopenharmony_ci#include "zcrypt_debug.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include "zcrypt_msgtype6.h"
3862306a36Sopenharmony_ci#include "zcrypt_msgtype50.h"
3962306a36Sopenharmony_ci#include "zcrypt_ccamisc.h"
4062306a36Sopenharmony_ci#include "zcrypt_ep11misc.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * Module description.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ciMODULE_AUTHOR("IBM Corporation");
4662306a36Sopenharmony_ciMODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \
4762306a36Sopenharmony_ci		   "Copyright IBM Corp. 2001, 2012");
4862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/*
5162306a36Sopenharmony_ci * zcrypt tracepoint functions
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_req);
5462306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_rep);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciDEFINE_SPINLOCK(zcrypt_list_lock);
5762306a36Sopenharmony_ciLIST_HEAD(zcrypt_card_list);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic atomic_t zcrypt_open_count = ATOMIC_INIT(0);
6062306a36Sopenharmony_cistatic atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciatomic_t zcrypt_rescan_req = ATOMIC_INIT(0);
6362306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_rescan_req);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic LIST_HEAD(zcrypt_ops_list);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Zcrypt related debug feature stuff. */
6862306a36Sopenharmony_cidebug_info_t *zcrypt_dbf_info;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Process a rescan of the transport layer.
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * Returns 1, if the rescan has been processed, otherwise 0.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_cistatic inline int zcrypt_process_rescan(void)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	if (atomic_read(&zcrypt_rescan_req)) {
7862306a36Sopenharmony_ci		atomic_set(&zcrypt_rescan_req, 0);
7962306a36Sopenharmony_ci		atomic_inc(&zcrypt_rescan_count);
8062306a36Sopenharmony_ci		ap_bus_force_rescan();
8162306a36Sopenharmony_ci		ZCRYPT_DBF_INFO("%s rescan count=%07d\n", __func__,
8262306a36Sopenharmony_ci				atomic_inc_return(&zcrypt_rescan_count));
8362306a36Sopenharmony_ci		return 1;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_civoid zcrypt_msgtype_register(struct zcrypt_ops *zops)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	list_add_tail(&zops->list, &zcrypt_ops_list);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_civoid zcrypt_msgtype_unregister(struct zcrypt_ops *zops)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	list_del_init(&zops->list);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistruct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct zcrypt_ops *zops;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	list_for_each_entry(zops, &zcrypt_ops_list, list)
10362306a36Sopenharmony_ci		if (zops->variant == variant &&
10462306a36Sopenharmony_ci		    (!strncmp(zops->name, name, sizeof(zops->name))))
10562306a36Sopenharmony_ci			return zops;
10662306a36Sopenharmony_ci	return NULL;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_msgtype);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * Multi device nodes extension functions.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistruct zcdn_device;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic struct class *zcrypt_class;
11762306a36Sopenharmony_cistatic dev_t zcrypt_devt;
11862306a36Sopenharmony_cistatic struct cdev zcrypt_cdev;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct zcdn_device {
12162306a36Sopenharmony_ci	struct device device;
12262306a36Sopenharmony_ci	struct ap_perms perms;
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device)
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define ZCDN_MAX_NAME 32
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int zcdn_create(const char *name);
13062306a36Sopenharmony_cistatic int zcdn_destroy(const char *name);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * Find zcdn device by name.
13462306a36Sopenharmony_ci * Returns reference to the zcdn device which needs to be released
13562306a36Sopenharmony_ci * with put_device() after use.
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_cistatic inline struct zcdn_device *find_zcdndev_by_name(const char *name)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct device *dev = class_find_device_by_name(zcrypt_class, name);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return dev ? to_zcdn_dev(dev) : NULL;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*
14562306a36Sopenharmony_ci * Find zcdn device by devt value.
14662306a36Sopenharmony_ci * Returns reference to the zcdn device which needs to be released
14762306a36Sopenharmony_ci * with put_device() after use.
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct device *dev = class_find_device_by_devt(zcrypt_class, devt);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return dev ? to_zcdn_dev(dev) : NULL;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic ssize_t ioctlmask_show(struct device *dev,
15762306a36Sopenharmony_ci			      struct device_attribute *attr,
15862306a36Sopenharmony_ci			      char *buf)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
16162306a36Sopenharmony_ci	int i, n;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ap_perms_mutex))
16462306a36Sopenharmony_ci		return -ERESTARTSYS;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	n = sysfs_emit(buf, "0x");
16762306a36Sopenharmony_ci	for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++)
16862306a36Sopenharmony_ci		n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.ioctlm[i]);
16962306a36Sopenharmony_ci	n += sysfs_emit_at(buf, n, "\n");
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return n;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic ssize_t ioctlmask_store(struct device *dev,
17762306a36Sopenharmony_ci			       struct device_attribute *attr,
17862306a36Sopenharmony_ci			       const char *buf, size_t count)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	int rc;
18162306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm,
18462306a36Sopenharmony_ci			       AP_IOCTLS, &ap_perms_mutex);
18562306a36Sopenharmony_ci	if (rc)
18662306a36Sopenharmony_ci		return rc;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return count;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ioctlmask);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic ssize_t apmask_show(struct device *dev,
19462306a36Sopenharmony_ci			   struct device_attribute *attr,
19562306a36Sopenharmony_ci			   char *buf)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
19862306a36Sopenharmony_ci	int i, n;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ap_perms_mutex))
20162306a36Sopenharmony_ci		return -ERESTARTSYS;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	n = sysfs_emit(buf, "0x");
20462306a36Sopenharmony_ci	for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++)
20562306a36Sopenharmony_ci		n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.apm[i]);
20662306a36Sopenharmony_ci	n += sysfs_emit_at(buf, n, "\n");
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	return n;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic ssize_t apmask_store(struct device *dev,
21462306a36Sopenharmony_ci			    struct device_attribute *attr,
21562306a36Sopenharmony_ci			    const char *buf, size_t count)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	int rc;
21862306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	rc = ap_parse_mask_str(buf, zcdndev->perms.apm,
22162306a36Sopenharmony_ci			       AP_DEVICES, &ap_perms_mutex);
22262306a36Sopenharmony_ci	if (rc)
22362306a36Sopenharmony_ci		return rc;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return count;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(apmask);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic ssize_t aqmask_show(struct device *dev,
23162306a36Sopenharmony_ci			   struct device_attribute *attr,
23262306a36Sopenharmony_ci			   char *buf)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
23562306a36Sopenharmony_ci	int i, n;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ap_perms_mutex))
23862306a36Sopenharmony_ci		return -ERESTARTSYS;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	n = sysfs_emit(buf, "0x");
24162306a36Sopenharmony_ci	for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++)
24262306a36Sopenharmony_ci		n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.aqm[i]);
24362306a36Sopenharmony_ci	n += sysfs_emit_at(buf, n, "\n");
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return n;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic ssize_t aqmask_store(struct device *dev,
25162306a36Sopenharmony_ci			    struct device_attribute *attr,
25262306a36Sopenharmony_ci			    const char *buf, size_t count)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	int rc;
25562306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	rc = ap_parse_mask_str(buf, zcdndev->perms.aqm,
25862306a36Sopenharmony_ci			       AP_DOMAINS, &ap_perms_mutex);
25962306a36Sopenharmony_ci	if (rc)
26062306a36Sopenharmony_ci		return rc;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return count;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(aqmask);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic ssize_t admask_show(struct device *dev,
26862306a36Sopenharmony_ci			   struct device_attribute *attr,
26962306a36Sopenharmony_ci			   char *buf)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
27262306a36Sopenharmony_ci	int i, n;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ap_perms_mutex))
27562306a36Sopenharmony_ci		return -ERESTARTSYS;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	n = sysfs_emit(buf, "0x");
27862306a36Sopenharmony_ci	for (i = 0; i < sizeof(zcdndev->perms.adm) / sizeof(long); i++)
27962306a36Sopenharmony_ci		n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.adm[i]);
28062306a36Sopenharmony_ci	n += sysfs_emit_at(buf, n, "\n");
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return n;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic ssize_t admask_store(struct device *dev,
28862306a36Sopenharmony_ci			    struct device_attribute *attr,
28962306a36Sopenharmony_ci			    const char *buf, size_t count)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	int rc;
29262306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	rc = ap_parse_mask_str(buf, zcdndev->perms.adm,
29562306a36Sopenharmony_ci			       AP_DOMAINS, &ap_perms_mutex);
29662306a36Sopenharmony_ci	if (rc)
29762306a36Sopenharmony_ci		return rc;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return count;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(admask);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic struct attribute *zcdn_dev_attrs[] = {
30562306a36Sopenharmony_ci	&dev_attr_ioctlmask.attr,
30662306a36Sopenharmony_ci	&dev_attr_apmask.attr,
30762306a36Sopenharmony_ci	&dev_attr_aqmask.attr,
30862306a36Sopenharmony_ci	&dev_attr_admask.attr,
30962306a36Sopenharmony_ci	NULL
31062306a36Sopenharmony_ci};
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic struct attribute_group zcdn_dev_attr_group = {
31362306a36Sopenharmony_ci	.attrs = zcdn_dev_attrs
31462306a36Sopenharmony_ci};
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic const struct attribute_group *zcdn_dev_attr_groups[] = {
31762306a36Sopenharmony_ci	&zcdn_dev_attr_group,
31862306a36Sopenharmony_ci	NULL
31962306a36Sopenharmony_ci};
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic ssize_t zcdn_create_store(const struct class *class,
32262306a36Sopenharmony_ci				 const struct class_attribute *attr,
32362306a36Sopenharmony_ci				 const char *buf, size_t count)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	int rc;
32662306a36Sopenharmony_ci	char name[ZCDN_MAX_NAME];
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	strscpy(name, skip_spaces(buf), sizeof(name));
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	rc = zcdn_create(strim(name));
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return rc ? rc : count;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic const struct class_attribute class_attr_zcdn_create =
33662306a36Sopenharmony_ci	__ATTR(create, 0600, NULL, zcdn_create_store);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic ssize_t zcdn_destroy_store(const struct class *class,
33962306a36Sopenharmony_ci				  const struct class_attribute *attr,
34062306a36Sopenharmony_ci				  const char *buf, size_t count)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	int rc;
34362306a36Sopenharmony_ci	char name[ZCDN_MAX_NAME];
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	strscpy(name, skip_spaces(buf), sizeof(name));
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	rc = zcdn_destroy(strim(name));
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return rc ? rc : count;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic const struct class_attribute class_attr_zcdn_destroy =
35362306a36Sopenharmony_ci	__ATTR(destroy, 0600, NULL, zcdn_destroy_store);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic void zcdn_device_release(struct device *dev)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct zcdn_device *zcdndev = to_zcdn_dev(dev);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ZCRYPT_DBF_INFO("%s releasing zcdn device %d:%d\n",
36062306a36Sopenharmony_ci			__func__, MAJOR(dev->devt), MINOR(dev->devt));
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	kfree(zcdndev);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int zcdn_create(const char *name)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	dev_t devt;
36862306a36Sopenharmony_ci	int i, rc = 0;
36962306a36Sopenharmony_ci	struct zcdn_device *zcdndev;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ap_perms_mutex))
37262306a36Sopenharmony_ci		return -ERESTARTSYS;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* check if device node with this name already exists */
37562306a36Sopenharmony_ci	if (name[0]) {
37662306a36Sopenharmony_ci		zcdndev = find_zcdndev_by_name(name);
37762306a36Sopenharmony_ci		if (zcdndev) {
37862306a36Sopenharmony_ci			put_device(&zcdndev->device);
37962306a36Sopenharmony_ci			rc = -EEXIST;
38062306a36Sopenharmony_ci			goto unlockout;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* find an unused minor number */
38562306a36Sopenharmony_ci	for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
38662306a36Sopenharmony_ci		devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
38762306a36Sopenharmony_ci		zcdndev = find_zcdndev_by_devt(devt);
38862306a36Sopenharmony_ci		if (zcdndev)
38962306a36Sopenharmony_ci			put_device(&zcdndev->device);
39062306a36Sopenharmony_ci		else
39162306a36Sopenharmony_ci			break;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	if (i == ZCRYPT_MAX_MINOR_NODES) {
39462306a36Sopenharmony_ci		rc = -ENOSPC;
39562306a36Sopenharmony_ci		goto unlockout;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* alloc and prepare a new zcdn device */
39962306a36Sopenharmony_ci	zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL);
40062306a36Sopenharmony_ci	if (!zcdndev) {
40162306a36Sopenharmony_ci		rc = -ENOMEM;
40262306a36Sopenharmony_ci		goto unlockout;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	zcdndev->device.release = zcdn_device_release;
40562306a36Sopenharmony_ci	zcdndev->device.class = zcrypt_class;
40662306a36Sopenharmony_ci	zcdndev->device.devt = devt;
40762306a36Sopenharmony_ci	zcdndev->device.groups = zcdn_dev_attr_groups;
40862306a36Sopenharmony_ci	if (name[0])
40962306a36Sopenharmony_ci		rc = dev_set_name(&zcdndev->device, "%s", name);
41062306a36Sopenharmony_ci	else
41162306a36Sopenharmony_ci		rc = dev_set_name(&zcdndev->device, ZCRYPT_NAME "_%d", (int)MINOR(devt));
41262306a36Sopenharmony_ci	if (rc) {
41362306a36Sopenharmony_ci		kfree(zcdndev);
41462306a36Sopenharmony_ci		goto unlockout;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci	rc = device_register(&zcdndev->device);
41762306a36Sopenharmony_ci	if (rc) {
41862306a36Sopenharmony_ci		put_device(&zcdndev->device);
41962306a36Sopenharmony_ci		goto unlockout;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	ZCRYPT_DBF_INFO("%s created zcdn device %d:%d\n",
42362306a36Sopenharmony_ci			__func__, MAJOR(devt), MINOR(devt));
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciunlockout:
42662306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
42762306a36Sopenharmony_ci	return rc;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic int zcdn_destroy(const char *name)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	int rc = 0;
43362306a36Sopenharmony_ci	struct zcdn_device *zcdndev;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ap_perms_mutex))
43662306a36Sopenharmony_ci		return -ERESTARTSYS;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* try to find this zcdn device */
43962306a36Sopenharmony_ci	zcdndev = find_zcdndev_by_name(name);
44062306a36Sopenharmony_ci	if (!zcdndev) {
44162306a36Sopenharmony_ci		rc = -ENOENT;
44262306a36Sopenharmony_ci		goto unlockout;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/*
44662306a36Sopenharmony_ci	 * The zcdn device is not hard destroyed. It is subject to
44762306a36Sopenharmony_ci	 * reference counting and thus just needs to be unregistered.
44862306a36Sopenharmony_ci	 */
44962306a36Sopenharmony_ci	put_device(&zcdndev->device);
45062306a36Sopenharmony_ci	device_unregister(&zcdndev->device);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciunlockout:
45362306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
45462306a36Sopenharmony_ci	return rc;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic void zcdn_destroy_all(void)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	int i;
46062306a36Sopenharmony_ci	dev_t devt;
46162306a36Sopenharmony_ci	struct zcdn_device *zcdndev;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	mutex_lock(&ap_perms_mutex);
46462306a36Sopenharmony_ci	for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
46562306a36Sopenharmony_ci		devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
46662306a36Sopenharmony_ci		zcdndev = find_zcdndev_by_devt(devt);
46762306a36Sopenharmony_ci		if (zcdndev) {
46862306a36Sopenharmony_ci			put_device(&zcdndev->device);
46962306a36Sopenharmony_ci			device_unregister(&zcdndev->device);
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci	mutex_unlock(&ap_perms_mutex);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/*
47662306a36Sopenharmony_ci * zcrypt_read (): Not supported beyond zcrypt 1.3.1.
47762306a36Sopenharmony_ci *
47862306a36Sopenharmony_ci * This function is not supported beyond zcrypt 1.3.1.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_cistatic ssize_t zcrypt_read(struct file *filp, char __user *buf,
48162306a36Sopenharmony_ci			   size_t count, loff_t *f_pos)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	return -EPERM;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/*
48762306a36Sopenharmony_ci * zcrypt_write(): Not allowed.
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * Write is not allowed
49062306a36Sopenharmony_ci */
49162306a36Sopenharmony_cistatic ssize_t zcrypt_write(struct file *filp, const char __user *buf,
49262306a36Sopenharmony_ci			    size_t count, loff_t *f_pos)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	return -EPERM;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/*
49862306a36Sopenharmony_ci * zcrypt_open(): Count number of users.
49962306a36Sopenharmony_ci *
50062306a36Sopenharmony_ci * Device open function to count number of users.
50162306a36Sopenharmony_ci */
50262306a36Sopenharmony_cistatic int zcrypt_open(struct inode *inode, struct file *filp)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct ap_perms *perms = &ap_perms;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (filp->f_inode->i_cdev == &zcrypt_cdev) {
50762306a36Sopenharmony_ci		struct zcdn_device *zcdndev;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		if (mutex_lock_interruptible(&ap_perms_mutex))
51062306a36Sopenharmony_ci			return -ERESTARTSYS;
51162306a36Sopenharmony_ci		zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
51262306a36Sopenharmony_ci		/* find returns a reference, no get_device() needed */
51362306a36Sopenharmony_ci		mutex_unlock(&ap_perms_mutex);
51462306a36Sopenharmony_ci		if (zcdndev)
51562306a36Sopenharmony_ci			perms = &zcdndev->perms;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci	filp->private_data = (void *)perms;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	atomic_inc(&zcrypt_open_count);
52062306a36Sopenharmony_ci	return stream_open(inode, filp);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci/*
52462306a36Sopenharmony_ci * zcrypt_release(): Count number of users.
52562306a36Sopenharmony_ci *
52662306a36Sopenharmony_ci * Device close function to count number of users.
52762306a36Sopenharmony_ci */
52862306a36Sopenharmony_cistatic int zcrypt_release(struct inode *inode, struct file *filp)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	if (filp->f_inode->i_cdev == &zcrypt_cdev) {
53162306a36Sopenharmony_ci		struct zcdn_device *zcdndev;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		mutex_lock(&ap_perms_mutex);
53462306a36Sopenharmony_ci		zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
53562306a36Sopenharmony_ci		mutex_unlock(&ap_perms_mutex);
53662306a36Sopenharmony_ci		if (zcdndev) {
53762306a36Sopenharmony_ci			/* 2 puts here: one for find, one for open */
53862306a36Sopenharmony_ci			put_device(&zcdndev->device);
53962306a36Sopenharmony_ci			put_device(&zcdndev->device);
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	atomic_dec(&zcrypt_open_count);
54462306a36Sopenharmony_ci	return 0;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic inline int zcrypt_check_ioctl(struct ap_perms *perms,
54862306a36Sopenharmony_ci				     unsigned int cmd)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	int rc = -EPERM;
55162306a36Sopenharmony_ci	int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) {
55462306a36Sopenharmony_ci		if (test_bit_inv(ioctlnr, perms->ioctlm))
55562306a36Sopenharmony_ci			rc = 0;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (rc)
55962306a36Sopenharmony_ci		ZCRYPT_DBF_WARN("%s ioctl check failed: ioctlnr=0x%04x rc=%d\n",
56062306a36Sopenharmony_ci				__func__, ioctlnr, rc);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return rc;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic inline bool zcrypt_check_card(struct ap_perms *perms, int card)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	return test_bit_inv(card, perms->apm) ? true : false;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic inline bool zcrypt_check_queue(struct ap_perms *perms, int queue)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	return test_bit_inv(queue, perms->aqm) ? true : false;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
57662306a36Sopenharmony_ci						     struct zcrypt_queue *zq,
57762306a36Sopenharmony_ci						     struct module **pmod,
57862306a36Sopenharmony_ci						     unsigned int weight)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	if (!zq || !try_module_get(zq->queue->ap_dev.device.driver->owner))
58162306a36Sopenharmony_ci		return NULL;
58262306a36Sopenharmony_ci	zcrypt_queue_get(zq);
58362306a36Sopenharmony_ci	get_device(&zq->queue->ap_dev.device);
58462306a36Sopenharmony_ci	atomic_add(weight, &zc->load);
58562306a36Sopenharmony_ci	atomic_add(weight, &zq->load);
58662306a36Sopenharmony_ci	zq->request_count++;
58762306a36Sopenharmony_ci	*pmod = zq->queue->ap_dev.device.driver->owner;
58862306a36Sopenharmony_ci	return zq;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic inline void zcrypt_drop_queue(struct zcrypt_card *zc,
59262306a36Sopenharmony_ci				     struct zcrypt_queue *zq,
59362306a36Sopenharmony_ci				     struct module *mod,
59462306a36Sopenharmony_ci				     unsigned int weight)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	zq->request_count--;
59762306a36Sopenharmony_ci	atomic_sub(weight, &zc->load);
59862306a36Sopenharmony_ci	atomic_sub(weight, &zq->load);
59962306a36Sopenharmony_ci	put_device(&zq->queue->ap_dev.device);
60062306a36Sopenharmony_ci	zcrypt_queue_put(zq);
60162306a36Sopenharmony_ci	module_put(mod);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic inline bool zcrypt_card_compare(struct zcrypt_card *zc,
60562306a36Sopenharmony_ci				       struct zcrypt_card *pref_zc,
60662306a36Sopenharmony_ci				       unsigned int weight,
60762306a36Sopenharmony_ci				       unsigned int pref_weight)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	if (!pref_zc)
61062306a36Sopenharmony_ci		return true;
61162306a36Sopenharmony_ci	weight += atomic_read(&zc->load);
61262306a36Sopenharmony_ci	pref_weight += atomic_read(&pref_zc->load);
61362306a36Sopenharmony_ci	if (weight == pref_weight)
61462306a36Sopenharmony_ci		return atomic64_read(&zc->card->total_request_count) <
61562306a36Sopenharmony_ci			atomic64_read(&pref_zc->card->total_request_count);
61662306a36Sopenharmony_ci	return weight < pref_weight;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
62062306a36Sopenharmony_ci					struct zcrypt_queue *pref_zq,
62162306a36Sopenharmony_ci					unsigned int weight,
62262306a36Sopenharmony_ci					unsigned int pref_weight)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	if (!pref_zq)
62562306a36Sopenharmony_ci		return true;
62662306a36Sopenharmony_ci	weight += atomic_read(&zq->load);
62762306a36Sopenharmony_ci	pref_weight += atomic_read(&pref_zq->load);
62862306a36Sopenharmony_ci	if (weight == pref_weight)
62962306a36Sopenharmony_ci		return zq->queue->total_request_count <
63062306a36Sopenharmony_ci			pref_zq->queue->total_request_count;
63162306a36Sopenharmony_ci	return weight < pref_weight;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/*
63562306a36Sopenharmony_ci * zcrypt ioctls.
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_cistatic long zcrypt_rsa_modexpo(struct ap_perms *perms,
63862306a36Sopenharmony_ci			       struct zcrypt_track *tr,
63962306a36Sopenharmony_ci			       struct ica_rsa_modexpo *mex)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct zcrypt_card *zc, *pref_zc;
64262306a36Sopenharmony_ci	struct zcrypt_queue *zq, *pref_zq;
64362306a36Sopenharmony_ci	struct ap_message ap_msg;
64462306a36Sopenharmony_ci	unsigned int wgt = 0, pref_wgt = 0;
64562306a36Sopenharmony_ci	unsigned int func_code;
64662306a36Sopenharmony_ci	int cpen, qpen, qid = 0, rc = -ENODEV;
64762306a36Sopenharmony_ci	struct module *mod;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	ap_init_message(&ap_msg);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (mex->outputdatalength < mex->inputdatalength) {
65462306a36Sopenharmony_ci		func_code = 0;
65562306a36Sopenharmony_ci		rc = -EINVAL;
65662306a36Sopenharmony_ci		goto out;
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/*
66062306a36Sopenharmony_ci	 * As long as outputdatalength is big enough, we can set the
66162306a36Sopenharmony_ci	 * outputdatalength equal to the inputdatalength, since that is the
66262306a36Sopenharmony_ci	 * number of bytes we will copy in any case
66362306a36Sopenharmony_ci	 */
66462306a36Sopenharmony_ci	mex->outputdatalength = mex->inputdatalength;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	rc = get_rsa_modex_fc(mex, &func_code);
66762306a36Sopenharmony_ci	if (rc)
66862306a36Sopenharmony_ci		goto out;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	pref_zc = NULL;
67162306a36Sopenharmony_ci	pref_zq = NULL;
67262306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
67362306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
67462306a36Sopenharmony_ci		/* Check for usable accelerator or CCA card */
67562306a36Sopenharmony_ci		if (!zc->online || !zc->card->config || zc->card->chkstop ||
67662306a36Sopenharmony_ci		    !(zc->card->functions & 0x18000000))
67762306a36Sopenharmony_ci			continue;
67862306a36Sopenharmony_ci		/* Check for size limits */
67962306a36Sopenharmony_ci		if (zc->min_mod_size > mex->inputdatalength ||
68062306a36Sopenharmony_ci		    zc->max_mod_size < mex->inputdatalength)
68162306a36Sopenharmony_ci			continue;
68262306a36Sopenharmony_ci		/* check if device node has admission for this card */
68362306a36Sopenharmony_ci		if (!zcrypt_check_card(perms, zc->card->id))
68462306a36Sopenharmony_ci			continue;
68562306a36Sopenharmony_ci		/* get weight index of the card device	*/
68662306a36Sopenharmony_ci		wgt = zc->speed_rating[func_code];
68762306a36Sopenharmony_ci		/* penalty if this msg was previously sent via this card */
68862306a36Sopenharmony_ci		cpen = (tr && tr->again_counter && tr->last_qid &&
68962306a36Sopenharmony_ci			AP_QID_CARD(tr->last_qid) == zc->card->id) ?
69062306a36Sopenharmony_ci			TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
69162306a36Sopenharmony_ci		if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
69262306a36Sopenharmony_ci			continue;
69362306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
69462306a36Sopenharmony_ci			/* check if device is usable and eligible */
69562306a36Sopenharmony_ci			if (!zq->online || !zq->ops->rsa_modexpo ||
69662306a36Sopenharmony_ci			    !zq->queue->config || zq->queue->chkstop)
69762306a36Sopenharmony_ci				continue;
69862306a36Sopenharmony_ci			/* check if device node has admission for this queue */
69962306a36Sopenharmony_ci			if (!zcrypt_check_queue(perms,
70062306a36Sopenharmony_ci						AP_QID_QUEUE(zq->queue->qid)))
70162306a36Sopenharmony_ci				continue;
70262306a36Sopenharmony_ci			/* penalty if the msg was previously sent at this qid */
70362306a36Sopenharmony_ci			qpen = (tr && tr->again_counter && tr->last_qid &&
70462306a36Sopenharmony_ci				tr->last_qid == zq->queue->qid) ?
70562306a36Sopenharmony_ci				TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
70662306a36Sopenharmony_ci			if (!zcrypt_queue_compare(zq, pref_zq,
70762306a36Sopenharmony_ci						  wgt + cpen + qpen, pref_wgt))
70862306a36Sopenharmony_ci				continue;
70962306a36Sopenharmony_ci			pref_zc = zc;
71062306a36Sopenharmony_ci			pref_zq = zq;
71162306a36Sopenharmony_ci			pref_wgt = wgt + cpen + qpen;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci	pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
71562306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	if (!pref_zq) {
71862306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("%s no matching queue found => ENODEV\n",
71962306a36Sopenharmony_ci			       __func__);
72062306a36Sopenharmony_ci		rc = -ENODEV;
72162306a36Sopenharmony_ci		goto out;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	qid = pref_zq->queue->qid;
72562306a36Sopenharmony_ci	rc = pref_zq->ops->rsa_modexpo(pref_zq, mex, &ap_msg);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
72862306a36Sopenharmony_ci	zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
72962306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ciout:
73262306a36Sopenharmony_ci	ap_release_message(&ap_msg);
73362306a36Sopenharmony_ci	if (tr) {
73462306a36Sopenharmony_ci		tr->last_rc = rc;
73562306a36Sopenharmony_ci		tr->last_qid = qid;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci	trace_s390_zcrypt_rep(mex, func_code, rc,
73862306a36Sopenharmony_ci			      AP_QID_CARD(qid), AP_QID_QUEUE(qid));
73962306a36Sopenharmony_ci	return rc;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic long zcrypt_rsa_crt(struct ap_perms *perms,
74362306a36Sopenharmony_ci			   struct zcrypt_track *tr,
74462306a36Sopenharmony_ci			   struct ica_rsa_modexpo_crt *crt)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct zcrypt_card *zc, *pref_zc;
74762306a36Sopenharmony_ci	struct zcrypt_queue *zq, *pref_zq;
74862306a36Sopenharmony_ci	struct ap_message ap_msg;
74962306a36Sopenharmony_ci	unsigned int wgt = 0, pref_wgt = 0;
75062306a36Sopenharmony_ci	unsigned int func_code;
75162306a36Sopenharmony_ci	int cpen, qpen, qid = 0, rc = -ENODEV;
75262306a36Sopenharmony_ci	struct module *mod;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	trace_s390_zcrypt_req(crt, TP_ICARSACRT);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	ap_init_message(&ap_msg);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (crt->outputdatalength < crt->inputdatalength) {
75962306a36Sopenharmony_ci		func_code = 0;
76062306a36Sopenharmony_ci		rc = -EINVAL;
76162306a36Sopenharmony_ci		goto out;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	/*
76562306a36Sopenharmony_ci	 * As long as outputdatalength is big enough, we can set the
76662306a36Sopenharmony_ci	 * outputdatalength equal to the inputdatalength, since that is the
76762306a36Sopenharmony_ci	 * number of bytes we will copy in any case
76862306a36Sopenharmony_ci	 */
76962306a36Sopenharmony_ci	crt->outputdatalength = crt->inputdatalength;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	rc = get_rsa_crt_fc(crt, &func_code);
77262306a36Sopenharmony_ci	if (rc)
77362306a36Sopenharmony_ci		goto out;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	pref_zc = NULL;
77662306a36Sopenharmony_ci	pref_zq = NULL;
77762306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
77862306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
77962306a36Sopenharmony_ci		/* Check for usable accelerator or CCA card */
78062306a36Sopenharmony_ci		if (!zc->online || !zc->card->config || zc->card->chkstop ||
78162306a36Sopenharmony_ci		    !(zc->card->functions & 0x18000000))
78262306a36Sopenharmony_ci			continue;
78362306a36Sopenharmony_ci		/* Check for size limits */
78462306a36Sopenharmony_ci		if (zc->min_mod_size > crt->inputdatalength ||
78562306a36Sopenharmony_ci		    zc->max_mod_size < crt->inputdatalength)
78662306a36Sopenharmony_ci			continue;
78762306a36Sopenharmony_ci		/* check if device node has admission for this card */
78862306a36Sopenharmony_ci		if (!zcrypt_check_card(perms, zc->card->id))
78962306a36Sopenharmony_ci			continue;
79062306a36Sopenharmony_ci		/* get weight index of the card device	*/
79162306a36Sopenharmony_ci		wgt = zc->speed_rating[func_code];
79262306a36Sopenharmony_ci		/* penalty if this msg was previously sent via this card */
79362306a36Sopenharmony_ci		cpen = (tr && tr->again_counter && tr->last_qid &&
79462306a36Sopenharmony_ci			AP_QID_CARD(tr->last_qid) == zc->card->id) ?
79562306a36Sopenharmony_ci			TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
79662306a36Sopenharmony_ci		if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
79762306a36Sopenharmony_ci			continue;
79862306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
79962306a36Sopenharmony_ci			/* check if device is usable and eligible */
80062306a36Sopenharmony_ci			if (!zq->online || !zq->ops->rsa_modexpo_crt ||
80162306a36Sopenharmony_ci			    !zq->queue->config || zq->queue->chkstop)
80262306a36Sopenharmony_ci				continue;
80362306a36Sopenharmony_ci			/* check if device node has admission for this queue */
80462306a36Sopenharmony_ci			if (!zcrypt_check_queue(perms,
80562306a36Sopenharmony_ci						AP_QID_QUEUE(zq->queue->qid)))
80662306a36Sopenharmony_ci				continue;
80762306a36Sopenharmony_ci			/* penalty if the msg was previously sent at this qid */
80862306a36Sopenharmony_ci			qpen = (tr && tr->again_counter && tr->last_qid &&
80962306a36Sopenharmony_ci				tr->last_qid == zq->queue->qid) ?
81062306a36Sopenharmony_ci				TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
81162306a36Sopenharmony_ci			if (!zcrypt_queue_compare(zq, pref_zq,
81262306a36Sopenharmony_ci						  wgt + cpen + qpen, pref_wgt))
81362306a36Sopenharmony_ci				continue;
81462306a36Sopenharmony_ci			pref_zc = zc;
81562306a36Sopenharmony_ci			pref_zq = zq;
81662306a36Sopenharmony_ci			pref_wgt = wgt + cpen + qpen;
81762306a36Sopenharmony_ci		}
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
82062306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (!pref_zq) {
82362306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("%s no matching queue found => ENODEV\n",
82462306a36Sopenharmony_ci			       __func__);
82562306a36Sopenharmony_ci		rc = -ENODEV;
82662306a36Sopenharmony_ci		goto out;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	qid = pref_zq->queue->qid;
83062306a36Sopenharmony_ci	rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt, &ap_msg);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
83362306a36Sopenharmony_ci	zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
83462306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ciout:
83762306a36Sopenharmony_ci	ap_release_message(&ap_msg);
83862306a36Sopenharmony_ci	if (tr) {
83962306a36Sopenharmony_ci		tr->last_rc = rc;
84062306a36Sopenharmony_ci		tr->last_qid = qid;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	trace_s390_zcrypt_rep(crt, func_code, rc,
84362306a36Sopenharmony_ci			      AP_QID_CARD(qid), AP_QID_QUEUE(qid));
84462306a36Sopenharmony_ci	return rc;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
84862306a36Sopenharmony_ci			      struct zcrypt_track *tr,
84962306a36Sopenharmony_ci			      struct ica_xcRB *xcrb)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	struct zcrypt_card *zc, *pref_zc;
85262306a36Sopenharmony_ci	struct zcrypt_queue *zq, *pref_zq;
85362306a36Sopenharmony_ci	struct ap_message ap_msg;
85462306a36Sopenharmony_ci	unsigned int wgt = 0, pref_wgt = 0;
85562306a36Sopenharmony_ci	unsigned int func_code;
85662306a36Sopenharmony_ci	unsigned short *domain, tdom;
85762306a36Sopenharmony_ci	int cpen, qpen, qid = 0, rc = -ENODEV;
85862306a36Sopenharmony_ci	struct module *mod;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	trace_s390_zcrypt_req(xcrb, TB_ZSECSENDCPRB);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	xcrb->status = 0;
86362306a36Sopenharmony_ci	ap_init_message(&ap_msg);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	rc = prep_cca_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
86662306a36Sopenharmony_ci	if (rc)
86762306a36Sopenharmony_ci		goto out;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	tdom = *domain;
87062306a36Sopenharmony_ci	if (perms != &ap_perms && tdom < AP_DOMAINS) {
87162306a36Sopenharmony_ci		if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
87262306a36Sopenharmony_ci			if (!test_bit_inv(tdom, perms->adm)) {
87362306a36Sopenharmony_ci				rc = -ENODEV;
87462306a36Sopenharmony_ci				goto out;
87562306a36Sopenharmony_ci			}
87662306a36Sopenharmony_ci		} else if ((ap_msg.flags & AP_MSG_FLAG_USAGE) == 0) {
87762306a36Sopenharmony_ci			rc = -EOPNOTSUPP;
87862306a36Sopenharmony_ci			goto out;
87962306a36Sopenharmony_ci		}
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci	/*
88262306a36Sopenharmony_ci	 * If a valid target domain is set and this domain is NOT a usage
88362306a36Sopenharmony_ci	 * domain but a control only domain, autoselect target domain.
88462306a36Sopenharmony_ci	 */
88562306a36Sopenharmony_ci	if (tdom < AP_DOMAINS &&
88662306a36Sopenharmony_ci	    !ap_test_config_usage_domain(tdom) &&
88762306a36Sopenharmony_ci	    ap_test_config_ctrl_domain(tdom))
88862306a36Sopenharmony_ci		tdom = AUTOSEL_DOM;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	pref_zc = NULL;
89162306a36Sopenharmony_ci	pref_zq = NULL;
89262306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
89362306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
89462306a36Sopenharmony_ci		/* Check for usable CCA card */
89562306a36Sopenharmony_ci		if (!zc->online || !zc->card->config || zc->card->chkstop ||
89662306a36Sopenharmony_ci		    !(zc->card->functions & 0x10000000))
89762306a36Sopenharmony_ci			continue;
89862306a36Sopenharmony_ci		/* Check for user selected CCA card */
89962306a36Sopenharmony_ci		if (xcrb->user_defined != AUTOSELECT &&
90062306a36Sopenharmony_ci		    xcrb->user_defined != zc->card->id)
90162306a36Sopenharmony_ci			continue;
90262306a36Sopenharmony_ci		/* check if request size exceeds card max msg size */
90362306a36Sopenharmony_ci		if (ap_msg.len > zc->card->maxmsgsize)
90462306a36Sopenharmony_ci			continue;
90562306a36Sopenharmony_ci		/* check if device node has admission for this card */
90662306a36Sopenharmony_ci		if (!zcrypt_check_card(perms, zc->card->id))
90762306a36Sopenharmony_ci			continue;
90862306a36Sopenharmony_ci		/* get weight index of the card device	*/
90962306a36Sopenharmony_ci		wgt = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
91062306a36Sopenharmony_ci		/* penalty if this msg was previously sent via this card */
91162306a36Sopenharmony_ci		cpen = (tr && tr->again_counter && tr->last_qid &&
91262306a36Sopenharmony_ci			AP_QID_CARD(tr->last_qid) == zc->card->id) ?
91362306a36Sopenharmony_ci			TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
91462306a36Sopenharmony_ci		if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
91562306a36Sopenharmony_ci			continue;
91662306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
91762306a36Sopenharmony_ci			/* check for device usable and eligible */
91862306a36Sopenharmony_ci			if (!zq->online || !zq->ops->send_cprb ||
91962306a36Sopenharmony_ci			    !zq->queue->config || zq->queue->chkstop ||
92062306a36Sopenharmony_ci			    (tdom != AUTOSEL_DOM &&
92162306a36Sopenharmony_ci			     tdom != AP_QID_QUEUE(zq->queue->qid)))
92262306a36Sopenharmony_ci				continue;
92362306a36Sopenharmony_ci			/* check if device node has admission for this queue */
92462306a36Sopenharmony_ci			if (!zcrypt_check_queue(perms,
92562306a36Sopenharmony_ci						AP_QID_QUEUE(zq->queue->qid)))
92662306a36Sopenharmony_ci				continue;
92762306a36Sopenharmony_ci			/* penalty if the msg was previously sent at this qid */
92862306a36Sopenharmony_ci			qpen = (tr && tr->again_counter && tr->last_qid &&
92962306a36Sopenharmony_ci				tr->last_qid == zq->queue->qid) ?
93062306a36Sopenharmony_ci				TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
93162306a36Sopenharmony_ci			if (!zcrypt_queue_compare(zq, pref_zq,
93262306a36Sopenharmony_ci						  wgt + cpen + qpen, pref_wgt))
93362306a36Sopenharmony_ci				continue;
93462306a36Sopenharmony_ci			pref_zc = zc;
93562306a36Sopenharmony_ci			pref_zq = zq;
93662306a36Sopenharmony_ci			pref_wgt = wgt + cpen + qpen;
93762306a36Sopenharmony_ci		}
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci	pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
94062306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (!pref_zq) {
94362306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("%s no match for address %02x.%04x => ENODEV\n",
94462306a36Sopenharmony_ci			       __func__, xcrb->user_defined, *domain);
94562306a36Sopenharmony_ci		rc = -ENODEV;
94662306a36Sopenharmony_ci		goto out;
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* in case of auto select, provide the correct domain */
95062306a36Sopenharmony_ci	qid = pref_zq->queue->qid;
95162306a36Sopenharmony_ci	if (*domain == AUTOSEL_DOM)
95262306a36Sopenharmony_ci		*domain = AP_QID_QUEUE(qid);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcrb, &ap_msg);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
95762306a36Sopenharmony_ci	zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
95862306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ciout:
96162306a36Sopenharmony_ci	ap_release_message(&ap_msg);
96262306a36Sopenharmony_ci	if (tr) {
96362306a36Sopenharmony_ci		tr->last_rc = rc;
96462306a36Sopenharmony_ci		tr->last_qid = qid;
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci	trace_s390_zcrypt_rep(xcrb, func_code, rc,
96762306a36Sopenharmony_ci			      AP_QID_CARD(qid), AP_QID_QUEUE(qid));
96862306a36Sopenharmony_ci	return rc;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cilong zcrypt_send_cprb(struct ica_xcRB *xcrb)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	return _zcrypt_send_cprb(false, &ap_perms, NULL, xcrb);
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_send_cprb);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic bool is_desired_ep11_card(unsigned int dev_id,
97862306a36Sopenharmony_ci				 unsigned short target_num,
97962306a36Sopenharmony_ci				 struct ep11_target_dev *targets)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	while (target_num-- > 0) {
98262306a36Sopenharmony_ci		if (targets->ap_id == dev_id || targets->ap_id == AUTOSEL_AP)
98362306a36Sopenharmony_ci			return true;
98462306a36Sopenharmony_ci		targets++;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci	return false;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic bool is_desired_ep11_queue(unsigned int dev_qid,
99062306a36Sopenharmony_ci				  unsigned short target_num,
99162306a36Sopenharmony_ci				  struct ep11_target_dev *targets)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	int card = AP_QID_CARD(dev_qid), dom = AP_QID_QUEUE(dev_qid);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	while (target_num-- > 0) {
99662306a36Sopenharmony_ci		if ((targets->ap_id == card || targets->ap_id == AUTOSEL_AP) &&
99762306a36Sopenharmony_ci		    (targets->dom_id == dom || targets->dom_id == AUTOSEL_DOM))
99862306a36Sopenharmony_ci			return true;
99962306a36Sopenharmony_ci		targets++;
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci	return false;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
100562306a36Sopenharmony_ci				   struct zcrypt_track *tr,
100662306a36Sopenharmony_ci				   struct ep11_urb *xcrb)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	struct zcrypt_card *zc, *pref_zc;
100962306a36Sopenharmony_ci	struct zcrypt_queue *zq, *pref_zq;
101062306a36Sopenharmony_ci	struct ep11_target_dev *targets;
101162306a36Sopenharmony_ci	unsigned short target_num;
101262306a36Sopenharmony_ci	unsigned int wgt = 0, pref_wgt = 0;
101362306a36Sopenharmony_ci	unsigned int func_code, domain;
101462306a36Sopenharmony_ci	struct ap_message ap_msg;
101562306a36Sopenharmony_ci	int cpen, qpen, qid = 0, rc = -ENODEV;
101662306a36Sopenharmony_ci	struct module *mod;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	ap_init_message(&ap_msg);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	target_num = (unsigned short)xcrb->targets_num;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/* empty list indicates autoselect (all available targets) */
102562306a36Sopenharmony_ci	targets = NULL;
102662306a36Sopenharmony_ci	if (target_num != 0) {
102762306a36Sopenharmony_ci		struct ep11_target_dev __user *uptr;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL);
103062306a36Sopenharmony_ci		if (!targets) {
103162306a36Sopenharmony_ci			func_code = 0;
103262306a36Sopenharmony_ci			rc = -ENOMEM;
103362306a36Sopenharmony_ci			goto out;
103462306a36Sopenharmony_ci		}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci		uptr = (struct ep11_target_dev __force __user *)xcrb->targets;
103762306a36Sopenharmony_ci		if (z_copy_from_user(userspace, targets, uptr,
103862306a36Sopenharmony_ci				     target_num * sizeof(*targets))) {
103962306a36Sopenharmony_ci			func_code = 0;
104062306a36Sopenharmony_ci			rc = -EFAULT;
104162306a36Sopenharmony_ci			goto out_free;
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	rc = prep_ep11_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
104662306a36Sopenharmony_ci	if (rc)
104762306a36Sopenharmony_ci		goto out_free;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	if (perms != &ap_perms && domain < AUTOSEL_DOM) {
105062306a36Sopenharmony_ci		if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
105162306a36Sopenharmony_ci			if (!test_bit_inv(domain, perms->adm)) {
105262306a36Sopenharmony_ci				rc = -ENODEV;
105362306a36Sopenharmony_ci				goto out_free;
105462306a36Sopenharmony_ci			}
105562306a36Sopenharmony_ci		} else if ((ap_msg.flags & AP_MSG_FLAG_USAGE) == 0) {
105662306a36Sopenharmony_ci			rc = -EOPNOTSUPP;
105762306a36Sopenharmony_ci			goto out_free;
105862306a36Sopenharmony_ci		}
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	pref_zc = NULL;
106262306a36Sopenharmony_ci	pref_zq = NULL;
106362306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
106462306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
106562306a36Sopenharmony_ci		/* Check for usable EP11 card */
106662306a36Sopenharmony_ci		if (!zc->online || !zc->card->config || zc->card->chkstop ||
106762306a36Sopenharmony_ci		    !(zc->card->functions & 0x04000000))
106862306a36Sopenharmony_ci			continue;
106962306a36Sopenharmony_ci		/* Check for user selected EP11 card */
107062306a36Sopenharmony_ci		if (targets &&
107162306a36Sopenharmony_ci		    !is_desired_ep11_card(zc->card->id, target_num, targets))
107262306a36Sopenharmony_ci			continue;
107362306a36Sopenharmony_ci		/* check if request size exceeds card max msg size */
107462306a36Sopenharmony_ci		if (ap_msg.len > zc->card->maxmsgsize)
107562306a36Sopenharmony_ci			continue;
107662306a36Sopenharmony_ci		/* check if device node has admission for this card */
107762306a36Sopenharmony_ci		if (!zcrypt_check_card(perms, zc->card->id))
107862306a36Sopenharmony_ci			continue;
107962306a36Sopenharmony_ci		/* get weight index of the card device	*/
108062306a36Sopenharmony_ci		wgt = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
108162306a36Sopenharmony_ci		/* penalty if this msg was previously sent via this card */
108262306a36Sopenharmony_ci		cpen = (tr && tr->again_counter && tr->last_qid &&
108362306a36Sopenharmony_ci			AP_QID_CARD(tr->last_qid) == zc->card->id) ?
108462306a36Sopenharmony_ci			TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0;
108562306a36Sopenharmony_ci		if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt))
108662306a36Sopenharmony_ci			continue;
108762306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
108862306a36Sopenharmony_ci			/* check if device is usable and eligible */
108962306a36Sopenharmony_ci			if (!zq->online || !zq->ops->send_ep11_cprb ||
109062306a36Sopenharmony_ci			    !zq->queue->config || zq->queue->chkstop ||
109162306a36Sopenharmony_ci			    (targets &&
109262306a36Sopenharmony_ci			     !is_desired_ep11_queue(zq->queue->qid,
109362306a36Sopenharmony_ci						    target_num, targets)))
109462306a36Sopenharmony_ci				continue;
109562306a36Sopenharmony_ci			/* check if device node has admission for this queue */
109662306a36Sopenharmony_ci			if (!zcrypt_check_queue(perms,
109762306a36Sopenharmony_ci						AP_QID_QUEUE(zq->queue->qid)))
109862306a36Sopenharmony_ci				continue;
109962306a36Sopenharmony_ci			/* penalty if the msg was previously sent at this qid */
110062306a36Sopenharmony_ci			qpen = (tr && tr->again_counter && tr->last_qid &&
110162306a36Sopenharmony_ci				tr->last_qid == zq->queue->qid) ?
110262306a36Sopenharmony_ci				TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0;
110362306a36Sopenharmony_ci			if (!zcrypt_queue_compare(zq, pref_zq,
110462306a36Sopenharmony_ci						  wgt + cpen + qpen, pref_wgt))
110562306a36Sopenharmony_ci				continue;
110662306a36Sopenharmony_ci			pref_zc = zc;
110762306a36Sopenharmony_ci			pref_zq = zq;
110862306a36Sopenharmony_ci			pref_wgt = wgt + cpen + qpen;
110962306a36Sopenharmony_ci		}
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci	pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
111262306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (!pref_zq) {
111562306a36Sopenharmony_ci		if (targets && target_num == 1) {
111662306a36Sopenharmony_ci			ZCRYPT_DBF_DBG("%s no match for address %02x.%04x => ENODEV\n",
111762306a36Sopenharmony_ci				       __func__, (int)targets->ap_id,
111862306a36Sopenharmony_ci				       (int)targets->dom_id);
111962306a36Sopenharmony_ci		} else if (targets) {
112062306a36Sopenharmony_ci			ZCRYPT_DBF_DBG("%s no match for %d target addrs => ENODEV\n",
112162306a36Sopenharmony_ci				       __func__, (int)target_num);
112262306a36Sopenharmony_ci		} else {
112362306a36Sopenharmony_ci			ZCRYPT_DBF_DBG("%s no match for address ff.ffff => ENODEV\n",
112462306a36Sopenharmony_ci				       __func__);
112562306a36Sopenharmony_ci		}
112662306a36Sopenharmony_ci		rc = -ENODEV;
112762306a36Sopenharmony_ci		goto out_free;
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	qid = pref_zq->queue->qid;
113162306a36Sopenharmony_ci	rc = pref_zq->ops->send_ep11_cprb(userspace, pref_zq, xcrb, &ap_msg);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
113462306a36Sopenharmony_ci	zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
113562306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ciout_free:
113862306a36Sopenharmony_ci	kfree(targets);
113962306a36Sopenharmony_ciout:
114062306a36Sopenharmony_ci	ap_release_message(&ap_msg);
114162306a36Sopenharmony_ci	if (tr) {
114262306a36Sopenharmony_ci		tr->last_rc = rc;
114362306a36Sopenharmony_ci		tr->last_qid = qid;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci	trace_s390_zcrypt_rep(xcrb, func_code, rc,
114662306a36Sopenharmony_ci			      AP_QID_CARD(qid), AP_QID_QUEUE(qid));
114762306a36Sopenharmony_ci	return rc;
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cilong zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	return _zcrypt_send_ep11_cprb(false, &ap_perms, NULL, xcrb);
115362306a36Sopenharmony_ci}
115462306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_send_ep11_cprb);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_cistatic long zcrypt_rng(char *buffer)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	struct zcrypt_card *zc, *pref_zc;
115962306a36Sopenharmony_ci	struct zcrypt_queue *zq, *pref_zq;
116062306a36Sopenharmony_ci	unsigned int wgt = 0, pref_wgt = 0;
116162306a36Sopenharmony_ci	unsigned int func_code;
116262306a36Sopenharmony_ci	struct ap_message ap_msg;
116362306a36Sopenharmony_ci	unsigned int domain;
116462306a36Sopenharmony_ci	int qid = 0, rc = -ENODEV;
116562306a36Sopenharmony_ci	struct module *mod;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	ap_init_message(&ap_msg);
117062306a36Sopenharmony_ci	rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain);
117162306a36Sopenharmony_ci	if (rc)
117262306a36Sopenharmony_ci		goto out;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	pref_zc = NULL;
117562306a36Sopenharmony_ci	pref_zq = NULL;
117662306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
117762306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
117862306a36Sopenharmony_ci		/* Check for usable CCA card */
117962306a36Sopenharmony_ci		if (!zc->online || !zc->card->config || zc->card->chkstop ||
118062306a36Sopenharmony_ci		    !(zc->card->functions & 0x10000000))
118162306a36Sopenharmony_ci			continue;
118262306a36Sopenharmony_ci		/* get weight index of the card device	*/
118362306a36Sopenharmony_ci		wgt = zc->speed_rating[func_code];
118462306a36Sopenharmony_ci		if (!zcrypt_card_compare(zc, pref_zc, wgt, pref_wgt))
118562306a36Sopenharmony_ci			continue;
118662306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
118762306a36Sopenharmony_ci			/* check if device is usable and eligible */
118862306a36Sopenharmony_ci			if (!zq->online || !zq->ops->rng ||
118962306a36Sopenharmony_ci			    !zq->queue->config || zq->queue->chkstop)
119062306a36Sopenharmony_ci				continue;
119162306a36Sopenharmony_ci			if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt))
119262306a36Sopenharmony_ci				continue;
119362306a36Sopenharmony_ci			pref_zc = zc;
119462306a36Sopenharmony_ci			pref_zq = zq;
119562306a36Sopenharmony_ci			pref_wgt = wgt;
119662306a36Sopenharmony_ci		}
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci	pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt);
119962306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (!pref_zq) {
120262306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("%s no matching queue found => ENODEV\n",
120362306a36Sopenharmony_ci			       __func__);
120462306a36Sopenharmony_ci		rc = -ENODEV;
120562306a36Sopenharmony_ci		goto out;
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	qid = pref_zq->queue->qid;
120962306a36Sopenharmony_ci	rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
121262306a36Sopenharmony_ci	zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
121362306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ciout:
121662306a36Sopenharmony_ci	ap_release_message(&ap_msg);
121762306a36Sopenharmony_ci	trace_s390_zcrypt_rep(buffer, func_code, rc,
121862306a36Sopenharmony_ci			      AP_QID_CARD(qid), AP_QID_QUEUE(qid));
121962306a36Sopenharmony_ci	return rc;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic void zcrypt_device_status_mask(struct zcrypt_device_status *devstatus)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	struct zcrypt_card *zc;
122562306a36Sopenharmony_ci	struct zcrypt_queue *zq;
122662306a36Sopenharmony_ci	struct zcrypt_device_status *stat;
122762306a36Sopenharmony_ci	int card, queue;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	memset(devstatus, 0, MAX_ZDEV_ENTRIES
123062306a36Sopenharmony_ci	       * sizeof(struct zcrypt_device_status));
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
123362306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
123462306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
123562306a36Sopenharmony_ci			card = AP_QID_CARD(zq->queue->qid);
123662306a36Sopenharmony_ci			if (card >= MAX_ZDEV_CARDIDS)
123762306a36Sopenharmony_ci				continue;
123862306a36Sopenharmony_ci			queue = AP_QID_QUEUE(zq->queue->qid);
123962306a36Sopenharmony_ci			stat = &devstatus[card * AP_DOMAINS + queue];
124062306a36Sopenharmony_ci			stat->hwtype = zc->card->ap_dev.device_type;
124162306a36Sopenharmony_ci			stat->functions = zc->card->functions >> 26;
124262306a36Sopenharmony_ci			stat->qid = zq->queue->qid;
124362306a36Sopenharmony_ci			stat->online = zq->online ? 0x01 : 0x00;
124462306a36Sopenharmony_ci		}
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_civoid zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	struct zcrypt_card *zc;
125262306a36Sopenharmony_ci	struct zcrypt_queue *zq;
125362306a36Sopenharmony_ci	struct zcrypt_device_status_ext *stat;
125462306a36Sopenharmony_ci	int card, queue;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	memset(devstatus, 0, MAX_ZDEV_ENTRIES_EXT
125762306a36Sopenharmony_ci	       * sizeof(struct zcrypt_device_status_ext));
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
126062306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
126162306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
126262306a36Sopenharmony_ci			card = AP_QID_CARD(zq->queue->qid);
126362306a36Sopenharmony_ci			queue = AP_QID_QUEUE(zq->queue->qid);
126462306a36Sopenharmony_ci			stat = &devstatus[card * AP_DOMAINS + queue];
126562306a36Sopenharmony_ci			stat->hwtype = zc->card->ap_dev.device_type;
126662306a36Sopenharmony_ci			stat->functions = zc->card->functions >> 26;
126762306a36Sopenharmony_ci			stat->qid = zq->queue->qid;
126862306a36Sopenharmony_ci			stat->online = zq->online ? 0x01 : 0x00;
126962306a36Sopenharmony_ci		}
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_device_status_mask_ext);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ciint zcrypt_device_status_ext(int card, int queue,
127662306a36Sopenharmony_ci			     struct zcrypt_device_status_ext *devstat)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	struct zcrypt_card *zc;
127962306a36Sopenharmony_ci	struct zcrypt_queue *zq;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	memset(devstat, 0, sizeof(*devstat));
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
128462306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
128562306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
128662306a36Sopenharmony_ci			if (card == AP_QID_CARD(zq->queue->qid) &&
128762306a36Sopenharmony_ci			    queue == AP_QID_QUEUE(zq->queue->qid)) {
128862306a36Sopenharmony_ci				devstat->hwtype = zc->card->ap_dev.device_type;
128962306a36Sopenharmony_ci				devstat->functions = zc->card->functions >> 26;
129062306a36Sopenharmony_ci				devstat->qid = zq->queue->qid;
129162306a36Sopenharmony_ci				devstat->online = zq->online ? 0x01 : 0x00;
129262306a36Sopenharmony_ci				spin_unlock(&zcrypt_list_lock);
129362306a36Sopenharmony_ci				return 0;
129462306a36Sopenharmony_ci			}
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	return -ENODEV;
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_device_status_ext);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cistatic void zcrypt_status_mask(char status[], size_t max_adapters)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	struct zcrypt_card *zc;
130662306a36Sopenharmony_ci	struct zcrypt_queue *zq;
130762306a36Sopenharmony_ci	int card;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	memset(status, 0, max_adapters);
131062306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
131162306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
131262306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
131362306a36Sopenharmony_ci			card = AP_QID_CARD(zq->queue->qid);
131462306a36Sopenharmony_ci			if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index ||
131562306a36Sopenharmony_ci			    card >= max_adapters)
131662306a36Sopenharmony_ci				continue;
131762306a36Sopenharmony_ci			status[card] = zc->online ? zc->user_space_type : 0x0d;
131862306a36Sopenharmony_ci		}
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic void zcrypt_qdepth_mask(char qdepth[], size_t max_adapters)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	struct zcrypt_card *zc;
132662306a36Sopenharmony_ci	struct zcrypt_queue *zq;
132762306a36Sopenharmony_ci	int card;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	memset(qdepth, 0, max_adapters);
133062306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
133162306a36Sopenharmony_ci	local_bh_disable();
133262306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
133362306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
133462306a36Sopenharmony_ci			card = AP_QID_CARD(zq->queue->qid);
133562306a36Sopenharmony_ci			if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index ||
133662306a36Sopenharmony_ci			    card >= max_adapters)
133762306a36Sopenharmony_ci				continue;
133862306a36Sopenharmony_ci			spin_lock(&zq->queue->lock);
133962306a36Sopenharmony_ci			qdepth[card] =
134062306a36Sopenharmony_ci				zq->queue->pendingq_count +
134162306a36Sopenharmony_ci				zq->queue->requestq_count;
134262306a36Sopenharmony_ci			spin_unlock(&zq->queue->lock);
134362306a36Sopenharmony_ci		}
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci	local_bh_enable();
134662306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic void zcrypt_perdev_reqcnt(u32 reqcnt[], size_t max_adapters)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	struct zcrypt_card *zc;
135262306a36Sopenharmony_ci	struct zcrypt_queue *zq;
135362306a36Sopenharmony_ci	int card;
135462306a36Sopenharmony_ci	u64 cnt;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	memset(reqcnt, 0, sizeof(int) * max_adapters);
135762306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
135862306a36Sopenharmony_ci	local_bh_disable();
135962306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
136062306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
136162306a36Sopenharmony_ci			card = AP_QID_CARD(zq->queue->qid);
136262306a36Sopenharmony_ci			if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index ||
136362306a36Sopenharmony_ci			    card >= max_adapters)
136462306a36Sopenharmony_ci				continue;
136562306a36Sopenharmony_ci			spin_lock(&zq->queue->lock);
136662306a36Sopenharmony_ci			cnt = zq->queue->total_request_count;
136762306a36Sopenharmony_ci			spin_unlock(&zq->queue->lock);
136862306a36Sopenharmony_ci			reqcnt[card] = (cnt < UINT_MAX) ? (u32)cnt : UINT_MAX;
136962306a36Sopenharmony_ci		}
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci	local_bh_enable();
137262306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic int zcrypt_pendingq_count(void)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	struct zcrypt_card *zc;
137862306a36Sopenharmony_ci	struct zcrypt_queue *zq;
137962306a36Sopenharmony_ci	int pendingq_count;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	pendingq_count = 0;
138262306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
138362306a36Sopenharmony_ci	local_bh_disable();
138462306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
138562306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
138662306a36Sopenharmony_ci			if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
138762306a36Sopenharmony_ci				continue;
138862306a36Sopenharmony_ci			spin_lock(&zq->queue->lock);
138962306a36Sopenharmony_ci			pendingq_count += zq->queue->pendingq_count;
139062306a36Sopenharmony_ci			spin_unlock(&zq->queue->lock);
139162306a36Sopenharmony_ci		}
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci	local_bh_enable();
139462306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
139562306a36Sopenharmony_ci	return pendingq_count;
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic int zcrypt_requestq_count(void)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct zcrypt_card *zc;
140162306a36Sopenharmony_ci	struct zcrypt_queue *zq;
140262306a36Sopenharmony_ci	int requestq_count;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	requestq_count = 0;
140562306a36Sopenharmony_ci	spin_lock(&zcrypt_list_lock);
140662306a36Sopenharmony_ci	local_bh_disable();
140762306a36Sopenharmony_ci	for_each_zcrypt_card(zc) {
140862306a36Sopenharmony_ci		for_each_zcrypt_queue(zq, zc) {
140962306a36Sopenharmony_ci			if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
141062306a36Sopenharmony_ci				continue;
141162306a36Sopenharmony_ci			spin_lock(&zq->queue->lock);
141262306a36Sopenharmony_ci			requestq_count += zq->queue->requestq_count;
141362306a36Sopenharmony_ci			spin_unlock(&zq->queue->lock);
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci	local_bh_enable();
141762306a36Sopenharmony_ci	spin_unlock(&zcrypt_list_lock);
141862306a36Sopenharmony_ci	return requestq_count;
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg)
142262306a36Sopenharmony_ci{
142362306a36Sopenharmony_ci	int rc;
142462306a36Sopenharmony_ci	struct zcrypt_track tr;
142562306a36Sopenharmony_ci	struct ica_rsa_modexpo mex;
142662306a36Sopenharmony_ci	struct ica_rsa_modexpo __user *umex = (void __user *)arg;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
142962306a36Sopenharmony_ci	if (copy_from_user(&mex, umex, sizeof(mex)))
143062306a36Sopenharmony_ci		return -EFAULT;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	do {
143362306a36Sopenharmony_ci		rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
143462306a36Sopenharmony_ci		if (rc == -EAGAIN)
143562306a36Sopenharmony_ci			tr.again_counter++;
143662306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
143762306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
143862306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
143962306a36Sopenharmony_ci		do {
144062306a36Sopenharmony_ci			rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
144162306a36Sopenharmony_ci			if (rc == -EAGAIN)
144262306a36Sopenharmony_ci				tr.again_counter++;
144362306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
144462306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
144562306a36Sopenharmony_ci		rc = -EIO;
144662306a36Sopenharmony_ci	if (rc) {
144762306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("ioctl ICARSAMODEXPO rc=%d\n", rc);
144862306a36Sopenharmony_ci		return rc;
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci	return put_user(mex.outputdatalength, &umex->outputdatalength);
145162306a36Sopenharmony_ci}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_cistatic int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	int rc;
145662306a36Sopenharmony_ci	struct zcrypt_track tr;
145762306a36Sopenharmony_ci	struct ica_rsa_modexpo_crt crt;
145862306a36Sopenharmony_ci	struct ica_rsa_modexpo_crt __user *ucrt = (void __user *)arg;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
146162306a36Sopenharmony_ci	if (copy_from_user(&crt, ucrt, sizeof(crt)))
146262306a36Sopenharmony_ci		return -EFAULT;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	do {
146562306a36Sopenharmony_ci		rc = zcrypt_rsa_crt(perms, &tr, &crt);
146662306a36Sopenharmony_ci		if (rc == -EAGAIN)
146762306a36Sopenharmony_ci			tr.again_counter++;
146862306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
146962306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
147062306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
147162306a36Sopenharmony_ci		do {
147262306a36Sopenharmony_ci			rc = zcrypt_rsa_crt(perms, &tr, &crt);
147362306a36Sopenharmony_ci			if (rc == -EAGAIN)
147462306a36Sopenharmony_ci				tr.again_counter++;
147562306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
147662306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
147762306a36Sopenharmony_ci		rc = -EIO;
147862306a36Sopenharmony_ci	if (rc) {
147962306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("ioctl ICARSACRT rc=%d\n", rc);
148062306a36Sopenharmony_ci		return rc;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci	return put_user(crt.outputdatalength, &ucrt->outputdatalength);
148362306a36Sopenharmony_ci}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_cistatic int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	int rc;
148862306a36Sopenharmony_ci	struct ica_xcRB xcrb;
148962306a36Sopenharmony_ci	struct zcrypt_track tr;
149062306a36Sopenharmony_ci	struct ica_xcRB __user *uxcrb = (void __user *)arg;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
149362306a36Sopenharmony_ci	if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
149462306a36Sopenharmony_ci		return -EFAULT;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	do {
149762306a36Sopenharmony_ci		rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
149862306a36Sopenharmony_ci		if (rc == -EAGAIN)
149962306a36Sopenharmony_ci			tr.again_counter++;
150062306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
150162306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
150262306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
150362306a36Sopenharmony_ci		do {
150462306a36Sopenharmony_ci			rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
150562306a36Sopenharmony_ci			if (rc == -EAGAIN)
150662306a36Sopenharmony_ci				tr.again_counter++;
150762306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
150862306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
150962306a36Sopenharmony_ci		rc = -EIO;
151062306a36Sopenharmony_ci	if (rc)
151162306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("ioctl ZSENDCPRB rc=%d status=0x%x\n",
151262306a36Sopenharmony_ci			       rc, xcrb.status);
151362306a36Sopenharmony_ci	if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
151462306a36Sopenharmony_ci		return -EFAULT;
151562306a36Sopenharmony_ci	return rc;
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_cistatic int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	int rc;
152162306a36Sopenharmony_ci	struct ep11_urb xcrb;
152262306a36Sopenharmony_ci	struct zcrypt_track tr;
152362306a36Sopenharmony_ci	struct ep11_urb __user *uxcrb = (void __user *)arg;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
152662306a36Sopenharmony_ci	if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
152762306a36Sopenharmony_ci		return -EFAULT;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	do {
153062306a36Sopenharmony_ci		rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
153162306a36Sopenharmony_ci		if (rc == -EAGAIN)
153262306a36Sopenharmony_ci			tr.again_counter++;
153362306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
153462306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
153562306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
153662306a36Sopenharmony_ci		do {
153762306a36Sopenharmony_ci			rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
153862306a36Sopenharmony_ci			if (rc == -EAGAIN)
153962306a36Sopenharmony_ci				tr.again_counter++;
154062306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
154162306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
154262306a36Sopenharmony_ci		rc = -EIO;
154362306a36Sopenharmony_ci	if (rc)
154462306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("ioctl ZSENDEP11CPRB rc=%d\n", rc);
154562306a36Sopenharmony_ci	if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
154662306a36Sopenharmony_ci		return -EFAULT;
154762306a36Sopenharmony_ci	return rc;
154862306a36Sopenharmony_ci}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
155162306a36Sopenharmony_ci				  unsigned long arg)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	int rc;
155462306a36Sopenharmony_ci	struct ap_perms *perms =
155562306a36Sopenharmony_ci		(struct ap_perms *)filp->private_data;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	rc = zcrypt_check_ioctl(perms, cmd);
155862306a36Sopenharmony_ci	if (rc)
155962306a36Sopenharmony_ci		return rc;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	switch (cmd) {
156262306a36Sopenharmony_ci	case ICARSAMODEXPO:
156362306a36Sopenharmony_ci		return icarsamodexpo_ioctl(perms, arg);
156462306a36Sopenharmony_ci	case ICARSACRT:
156562306a36Sopenharmony_ci		return icarsacrt_ioctl(perms, arg);
156662306a36Sopenharmony_ci	case ZSECSENDCPRB:
156762306a36Sopenharmony_ci		return zsecsendcprb_ioctl(perms, arg);
156862306a36Sopenharmony_ci	case ZSENDEP11CPRB:
156962306a36Sopenharmony_ci		return zsendep11cprb_ioctl(perms, arg);
157062306a36Sopenharmony_ci	case ZCRYPT_DEVICE_STATUS: {
157162306a36Sopenharmony_ci		struct zcrypt_device_status_ext *device_status;
157262306a36Sopenharmony_ci		size_t total_size = MAX_ZDEV_ENTRIES_EXT
157362306a36Sopenharmony_ci			* sizeof(struct zcrypt_device_status_ext);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci		device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
157662306a36Sopenharmony_ci					       sizeof(struct zcrypt_device_status_ext),
157762306a36Sopenharmony_ci					       GFP_KERNEL);
157862306a36Sopenharmony_ci		if (!device_status)
157962306a36Sopenharmony_ci			return -ENOMEM;
158062306a36Sopenharmony_ci		zcrypt_device_status_mask_ext(device_status);
158162306a36Sopenharmony_ci		if (copy_to_user((char __user *)arg, device_status,
158262306a36Sopenharmony_ci				 total_size))
158362306a36Sopenharmony_ci			rc = -EFAULT;
158462306a36Sopenharmony_ci		kvfree(device_status);
158562306a36Sopenharmony_ci		return rc;
158662306a36Sopenharmony_ci	}
158762306a36Sopenharmony_ci	case ZCRYPT_STATUS_MASK: {
158862306a36Sopenharmony_ci		char status[AP_DEVICES];
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		zcrypt_status_mask(status, AP_DEVICES);
159162306a36Sopenharmony_ci		if (copy_to_user((char __user *)arg, status, sizeof(status)))
159262306a36Sopenharmony_ci			return -EFAULT;
159362306a36Sopenharmony_ci		return 0;
159462306a36Sopenharmony_ci	}
159562306a36Sopenharmony_ci	case ZCRYPT_QDEPTH_MASK: {
159662306a36Sopenharmony_ci		char qdepth[AP_DEVICES];
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		zcrypt_qdepth_mask(qdepth, AP_DEVICES);
159962306a36Sopenharmony_ci		if (copy_to_user((char __user *)arg, qdepth, sizeof(qdepth)))
160062306a36Sopenharmony_ci			return -EFAULT;
160162306a36Sopenharmony_ci		return 0;
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci	case ZCRYPT_PERDEV_REQCNT: {
160462306a36Sopenharmony_ci		u32 *reqcnt;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci		reqcnt = kcalloc(AP_DEVICES, sizeof(u32), GFP_KERNEL);
160762306a36Sopenharmony_ci		if (!reqcnt)
160862306a36Sopenharmony_ci			return -ENOMEM;
160962306a36Sopenharmony_ci		zcrypt_perdev_reqcnt(reqcnt, AP_DEVICES);
161062306a36Sopenharmony_ci		if (copy_to_user((int __user *)arg, reqcnt,
161162306a36Sopenharmony_ci				 sizeof(u32) * AP_DEVICES))
161262306a36Sopenharmony_ci			rc = -EFAULT;
161362306a36Sopenharmony_ci		kfree(reqcnt);
161462306a36Sopenharmony_ci		return rc;
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci	case Z90STAT_REQUESTQ_COUNT:
161762306a36Sopenharmony_ci		return put_user(zcrypt_requestq_count(), (int __user *)arg);
161862306a36Sopenharmony_ci	case Z90STAT_PENDINGQ_COUNT:
161962306a36Sopenharmony_ci		return put_user(zcrypt_pendingq_count(), (int __user *)arg);
162062306a36Sopenharmony_ci	case Z90STAT_TOTALOPEN_COUNT:
162162306a36Sopenharmony_ci		return put_user(atomic_read(&zcrypt_open_count),
162262306a36Sopenharmony_ci				(int __user *)arg);
162362306a36Sopenharmony_ci	case Z90STAT_DOMAIN_INDEX:
162462306a36Sopenharmony_ci		return put_user(ap_domain_index, (int __user *)arg);
162562306a36Sopenharmony_ci	/*
162662306a36Sopenharmony_ci	 * Deprecated ioctls
162762306a36Sopenharmony_ci	 */
162862306a36Sopenharmony_ci	case ZDEVICESTATUS: {
162962306a36Sopenharmony_ci		/* the old ioctl supports only 64 adapters */
163062306a36Sopenharmony_ci		struct zcrypt_device_status *device_status;
163162306a36Sopenharmony_ci		size_t total_size = MAX_ZDEV_ENTRIES
163262306a36Sopenharmony_ci			* sizeof(struct zcrypt_device_status);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci		device_status = kzalloc(total_size, GFP_KERNEL);
163562306a36Sopenharmony_ci		if (!device_status)
163662306a36Sopenharmony_ci			return -ENOMEM;
163762306a36Sopenharmony_ci		zcrypt_device_status_mask(device_status);
163862306a36Sopenharmony_ci		if (copy_to_user((char __user *)arg, device_status,
163962306a36Sopenharmony_ci				 total_size))
164062306a36Sopenharmony_ci			rc = -EFAULT;
164162306a36Sopenharmony_ci		kfree(device_status);
164262306a36Sopenharmony_ci		return rc;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci	case Z90STAT_STATUS_MASK: {
164562306a36Sopenharmony_ci		/* the old ioctl supports only 64 adapters */
164662306a36Sopenharmony_ci		char status[MAX_ZDEV_CARDIDS];
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci		zcrypt_status_mask(status, MAX_ZDEV_CARDIDS);
164962306a36Sopenharmony_ci		if (copy_to_user((char __user *)arg, status, sizeof(status)))
165062306a36Sopenharmony_ci			return -EFAULT;
165162306a36Sopenharmony_ci		return 0;
165262306a36Sopenharmony_ci	}
165362306a36Sopenharmony_ci	case Z90STAT_QDEPTH_MASK: {
165462306a36Sopenharmony_ci		/* the old ioctl supports only 64 adapters */
165562306a36Sopenharmony_ci		char qdepth[MAX_ZDEV_CARDIDS];
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci		zcrypt_qdepth_mask(qdepth, MAX_ZDEV_CARDIDS);
165862306a36Sopenharmony_ci		if (copy_to_user((char __user *)arg, qdepth, sizeof(qdepth)))
165962306a36Sopenharmony_ci			return -EFAULT;
166062306a36Sopenharmony_ci		return 0;
166162306a36Sopenharmony_ci	}
166262306a36Sopenharmony_ci	case Z90STAT_PERDEV_REQCNT: {
166362306a36Sopenharmony_ci		/* the old ioctl supports only 64 adapters */
166462306a36Sopenharmony_ci		u32 reqcnt[MAX_ZDEV_CARDIDS];
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci		zcrypt_perdev_reqcnt(reqcnt, MAX_ZDEV_CARDIDS);
166762306a36Sopenharmony_ci		if (copy_to_user((int __user *)arg, reqcnt, sizeof(reqcnt)))
166862306a36Sopenharmony_ci			return -EFAULT;
166962306a36Sopenharmony_ci		return 0;
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci	/* unknown ioctl number */
167262306a36Sopenharmony_ci	default:
167362306a36Sopenharmony_ci		ZCRYPT_DBF_DBG("unknown ioctl 0x%08x\n", cmd);
167462306a36Sopenharmony_ci		return -ENOIOCTLCMD;
167562306a36Sopenharmony_ci	}
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
167962306a36Sopenharmony_ci/*
168062306a36Sopenharmony_ci * ioctl32 conversion routines
168162306a36Sopenharmony_ci */
168262306a36Sopenharmony_cistruct compat_ica_rsa_modexpo {
168362306a36Sopenharmony_ci	compat_uptr_t	inputdata;
168462306a36Sopenharmony_ci	unsigned int	inputdatalength;
168562306a36Sopenharmony_ci	compat_uptr_t	outputdata;
168662306a36Sopenharmony_ci	unsigned int	outputdatalength;
168762306a36Sopenharmony_ci	compat_uptr_t	b_key;
168862306a36Sopenharmony_ci	compat_uptr_t	n_modulus;
168962306a36Sopenharmony_ci};
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic long trans_modexpo32(struct ap_perms *perms, struct file *filp,
169262306a36Sopenharmony_ci			    unsigned int cmd, unsigned long arg)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
169562306a36Sopenharmony_ci	struct compat_ica_rsa_modexpo mex32;
169662306a36Sopenharmony_ci	struct ica_rsa_modexpo mex64;
169762306a36Sopenharmony_ci	struct zcrypt_track tr;
169862306a36Sopenharmony_ci	long rc;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
170162306a36Sopenharmony_ci	if (copy_from_user(&mex32, umex32, sizeof(mex32)))
170262306a36Sopenharmony_ci		return -EFAULT;
170362306a36Sopenharmony_ci	mex64.inputdata = compat_ptr(mex32.inputdata);
170462306a36Sopenharmony_ci	mex64.inputdatalength = mex32.inputdatalength;
170562306a36Sopenharmony_ci	mex64.outputdata = compat_ptr(mex32.outputdata);
170662306a36Sopenharmony_ci	mex64.outputdatalength = mex32.outputdatalength;
170762306a36Sopenharmony_ci	mex64.b_key = compat_ptr(mex32.b_key);
170862306a36Sopenharmony_ci	mex64.n_modulus = compat_ptr(mex32.n_modulus);
170962306a36Sopenharmony_ci	do {
171062306a36Sopenharmony_ci		rc = zcrypt_rsa_modexpo(perms, &tr, &mex64);
171162306a36Sopenharmony_ci		if (rc == -EAGAIN)
171262306a36Sopenharmony_ci			tr.again_counter++;
171362306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
171462306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
171562306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
171662306a36Sopenharmony_ci		do {
171762306a36Sopenharmony_ci			rc = zcrypt_rsa_modexpo(perms, &tr, &mex64);
171862306a36Sopenharmony_ci			if (rc == -EAGAIN)
171962306a36Sopenharmony_ci				tr.again_counter++;
172062306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
172162306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
172262306a36Sopenharmony_ci		rc = -EIO;
172362306a36Sopenharmony_ci	if (rc)
172462306a36Sopenharmony_ci		return rc;
172562306a36Sopenharmony_ci	return put_user(mex64.outputdatalength,
172662306a36Sopenharmony_ci			&umex32->outputdatalength);
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_cistruct compat_ica_rsa_modexpo_crt {
173062306a36Sopenharmony_ci	compat_uptr_t	inputdata;
173162306a36Sopenharmony_ci	unsigned int	inputdatalength;
173262306a36Sopenharmony_ci	compat_uptr_t	outputdata;
173362306a36Sopenharmony_ci	unsigned int	outputdatalength;
173462306a36Sopenharmony_ci	compat_uptr_t	bp_key;
173562306a36Sopenharmony_ci	compat_uptr_t	bq_key;
173662306a36Sopenharmony_ci	compat_uptr_t	np_prime;
173762306a36Sopenharmony_ci	compat_uptr_t	nq_prime;
173862306a36Sopenharmony_ci	compat_uptr_t	u_mult_inv;
173962306a36Sopenharmony_ci};
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_cistatic long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
174262306a36Sopenharmony_ci				unsigned int cmd, unsigned long arg)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
174562306a36Sopenharmony_ci	struct compat_ica_rsa_modexpo_crt crt32;
174662306a36Sopenharmony_ci	struct ica_rsa_modexpo_crt crt64;
174762306a36Sopenharmony_ci	struct zcrypt_track tr;
174862306a36Sopenharmony_ci	long rc;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
175162306a36Sopenharmony_ci	if (copy_from_user(&crt32, ucrt32, sizeof(crt32)))
175262306a36Sopenharmony_ci		return -EFAULT;
175362306a36Sopenharmony_ci	crt64.inputdata = compat_ptr(crt32.inputdata);
175462306a36Sopenharmony_ci	crt64.inputdatalength = crt32.inputdatalength;
175562306a36Sopenharmony_ci	crt64.outputdata = compat_ptr(crt32.outputdata);
175662306a36Sopenharmony_ci	crt64.outputdatalength = crt32.outputdatalength;
175762306a36Sopenharmony_ci	crt64.bp_key = compat_ptr(crt32.bp_key);
175862306a36Sopenharmony_ci	crt64.bq_key = compat_ptr(crt32.bq_key);
175962306a36Sopenharmony_ci	crt64.np_prime = compat_ptr(crt32.np_prime);
176062306a36Sopenharmony_ci	crt64.nq_prime = compat_ptr(crt32.nq_prime);
176162306a36Sopenharmony_ci	crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
176262306a36Sopenharmony_ci	do {
176362306a36Sopenharmony_ci		rc = zcrypt_rsa_crt(perms, &tr, &crt64);
176462306a36Sopenharmony_ci		if (rc == -EAGAIN)
176562306a36Sopenharmony_ci			tr.again_counter++;
176662306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
176762306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
176862306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
176962306a36Sopenharmony_ci		do {
177062306a36Sopenharmony_ci			rc = zcrypt_rsa_crt(perms, &tr, &crt64);
177162306a36Sopenharmony_ci			if (rc == -EAGAIN)
177262306a36Sopenharmony_ci				tr.again_counter++;
177362306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
177462306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
177562306a36Sopenharmony_ci		rc = -EIO;
177662306a36Sopenharmony_ci	if (rc)
177762306a36Sopenharmony_ci		return rc;
177862306a36Sopenharmony_ci	return put_user(crt64.outputdatalength,
177962306a36Sopenharmony_ci			&ucrt32->outputdatalength);
178062306a36Sopenharmony_ci}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_cistruct compat_ica_xcrb {
178362306a36Sopenharmony_ci	unsigned short	agent_ID;
178462306a36Sopenharmony_ci	unsigned int	user_defined;
178562306a36Sopenharmony_ci	unsigned short	request_ID;
178662306a36Sopenharmony_ci	unsigned int	request_control_blk_length;
178762306a36Sopenharmony_ci	unsigned char	padding1[16 - sizeof(compat_uptr_t)];
178862306a36Sopenharmony_ci	compat_uptr_t	request_control_blk_addr;
178962306a36Sopenharmony_ci	unsigned int	request_data_length;
179062306a36Sopenharmony_ci	char		padding2[16 - sizeof(compat_uptr_t)];
179162306a36Sopenharmony_ci	compat_uptr_t	request_data_address;
179262306a36Sopenharmony_ci	unsigned int	reply_control_blk_length;
179362306a36Sopenharmony_ci	char		padding3[16 - sizeof(compat_uptr_t)];
179462306a36Sopenharmony_ci	compat_uptr_t	reply_control_blk_addr;
179562306a36Sopenharmony_ci	unsigned int	reply_data_length;
179662306a36Sopenharmony_ci	char		padding4[16 - sizeof(compat_uptr_t)];
179762306a36Sopenharmony_ci	compat_uptr_t	reply_data_addr;
179862306a36Sopenharmony_ci	unsigned short	priority_window;
179962306a36Sopenharmony_ci	unsigned int	status;
180062306a36Sopenharmony_ci} __packed;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic long trans_xcrb32(struct ap_perms *perms, struct file *filp,
180362306a36Sopenharmony_ci			 unsigned int cmd, unsigned long arg)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct compat_ica_xcrb __user *uxcrb32 = compat_ptr(arg);
180662306a36Sopenharmony_ci	struct compat_ica_xcrb xcrb32;
180762306a36Sopenharmony_ci	struct zcrypt_track tr;
180862306a36Sopenharmony_ci	struct ica_xcRB xcrb64;
180962306a36Sopenharmony_ci	long rc;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	memset(&tr, 0, sizeof(tr));
181262306a36Sopenharmony_ci	if (copy_from_user(&xcrb32, uxcrb32, sizeof(xcrb32)))
181362306a36Sopenharmony_ci		return -EFAULT;
181462306a36Sopenharmony_ci	xcrb64.agent_ID = xcrb32.agent_ID;
181562306a36Sopenharmony_ci	xcrb64.user_defined = xcrb32.user_defined;
181662306a36Sopenharmony_ci	xcrb64.request_ID = xcrb32.request_ID;
181762306a36Sopenharmony_ci	xcrb64.request_control_blk_length =
181862306a36Sopenharmony_ci		xcrb32.request_control_blk_length;
181962306a36Sopenharmony_ci	xcrb64.request_control_blk_addr =
182062306a36Sopenharmony_ci		compat_ptr(xcrb32.request_control_blk_addr);
182162306a36Sopenharmony_ci	xcrb64.request_data_length =
182262306a36Sopenharmony_ci		xcrb32.request_data_length;
182362306a36Sopenharmony_ci	xcrb64.request_data_address =
182462306a36Sopenharmony_ci		compat_ptr(xcrb32.request_data_address);
182562306a36Sopenharmony_ci	xcrb64.reply_control_blk_length =
182662306a36Sopenharmony_ci		xcrb32.reply_control_blk_length;
182762306a36Sopenharmony_ci	xcrb64.reply_control_blk_addr =
182862306a36Sopenharmony_ci		compat_ptr(xcrb32.reply_control_blk_addr);
182962306a36Sopenharmony_ci	xcrb64.reply_data_length = xcrb32.reply_data_length;
183062306a36Sopenharmony_ci	xcrb64.reply_data_addr =
183162306a36Sopenharmony_ci		compat_ptr(xcrb32.reply_data_addr);
183262306a36Sopenharmony_ci	xcrb64.priority_window = xcrb32.priority_window;
183362306a36Sopenharmony_ci	xcrb64.status = xcrb32.status;
183462306a36Sopenharmony_ci	do {
183562306a36Sopenharmony_ci		rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
183662306a36Sopenharmony_ci		if (rc == -EAGAIN)
183762306a36Sopenharmony_ci			tr.again_counter++;
183862306a36Sopenharmony_ci	} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
183962306a36Sopenharmony_ci	/* on failure: retry once again after a requested rescan */
184062306a36Sopenharmony_ci	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
184162306a36Sopenharmony_ci		do {
184262306a36Sopenharmony_ci			rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
184362306a36Sopenharmony_ci			if (rc == -EAGAIN)
184462306a36Sopenharmony_ci				tr.again_counter++;
184562306a36Sopenharmony_ci		} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
184662306a36Sopenharmony_ci	if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
184762306a36Sopenharmony_ci		rc = -EIO;
184862306a36Sopenharmony_ci	xcrb32.reply_control_blk_length = xcrb64.reply_control_blk_length;
184962306a36Sopenharmony_ci	xcrb32.reply_data_length = xcrb64.reply_data_length;
185062306a36Sopenharmony_ci	xcrb32.status = xcrb64.status;
185162306a36Sopenharmony_ci	if (copy_to_user(uxcrb32, &xcrb32, sizeof(xcrb32)))
185262306a36Sopenharmony_ci		return -EFAULT;
185362306a36Sopenharmony_ci	return rc;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_cistatic long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
185762306a36Sopenharmony_ci				unsigned long arg)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	int rc;
186062306a36Sopenharmony_ci	struct ap_perms *perms =
186162306a36Sopenharmony_ci		(struct ap_perms *)filp->private_data;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	rc = zcrypt_check_ioctl(perms, cmd);
186462306a36Sopenharmony_ci	if (rc)
186562306a36Sopenharmony_ci		return rc;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (cmd == ICARSAMODEXPO)
186862306a36Sopenharmony_ci		return trans_modexpo32(perms, filp, cmd, arg);
186962306a36Sopenharmony_ci	if (cmd == ICARSACRT)
187062306a36Sopenharmony_ci		return trans_modexpo_crt32(perms, filp, cmd, arg);
187162306a36Sopenharmony_ci	if (cmd == ZSECSENDCPRB)
187262306a36Sopenharmony_ci		return trans_xcrb32(perms, filp, cmd, arg);
187362306a36Sopenharmony_ci	return zcrypt_unlocked_ioctl(filp, cmd, arg);
187462306a36Sopenharmony_ci}
187562306a36Sopenharmony_ci#endif
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci/*
187862306a36Sopenharmony_ci * Misc device file operations.
187962306a36Sopenharmony_ci */
188062306a36Sopenharmony_cistatic const struct file_operations zcrypt_fops = {
188162306a36Sopenharmony_ci	.owner		= THIS_MODULE,
188262306a36Sopenharmony_ci	.read		= zcrypt_read,
188362306a36Sopenharmony_ci	.write		= zcrypt_write,
188462306a36Sopenharmony_ci	.unlocked_ioctl	= zcrypt_unlocked_ioctl,
188562306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
188662306a36Sopenharmony_ci	.compat_ioctl	= zcrypt_compat_ioctl,
188762306a36Sopenharmony_ci#endif
188862306a36Sopenharmony_ci	.open		= zcrypt_open,
188962306a36Sopenharmony_ci	.release	= zcrypt_release,
189062306a36Sopenharmony_ci	.llseek		= no_llseek,
189162306a36Sopenharmony_ci};
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci/*
189462306a36Sopenharmony_ci * Misc device.
189562306a36Sopenharmony_ci */
189662306a36Sopenharmony_cistatic struct miscdevice zcrypt_misc_device = {
189762306a36Sopenharmony_ci	.minor	    = MISC_DYNAMIC_MINOR,
189862306a36Sopenharmony_ci	.name	    = "z90crypt",
189962306a36Sopenharmony_ci	.fops	    = &zcrypt_fops,
190062306a36Sopenharmony_ci};
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_cistatic int zcrypt_rng_device_count;
190362306a36Sopenharmony_cistatic u32 *zcrypt_rng_buffer;
190462306a36Sopenharmony_cistatic int zcrypt_rng_buffer_index;
190562306a36Sopenharmony_cistatic DEFINE_MUTEX(zcrypt_rng_mutex);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_cistatic int zcrypt_rng_data_read(struct hwrng *rng, u32 *data)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	int rc;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/*
191262306a36Sopenharmony_ci	 * We don't need locking here because the RNG API guarantees serialized
191362306a36Sopenharmony_ci	 * read method calls.
191462306a36Sopenharmony_ci	 */
191562306a36Sopenharmony_ci	if (zcrypt_rng_buffer_index == 0) {
191662306a36Sopenharmony_ci		rc = zcrypt_rng((char *)zcrypt_rng_buffer);
191762306a36Sopenharmony_ci		/* on failure: retry once again after a requested rescan */
191862306a36Sopenharmony_ci		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
191962306a36Sopenharmony_ci			rc = zcrypt_rng((char *)zcrypt_rng_buffer);
192062306a36Sopenharmony_ci		if (rc < 0)
192162306a36Sopenharmony_ci			return -EIO;
192262306a36Sopenharmony_ci		zcrypt_rng_buffer_index = rc / sizeof(*data);
192362306a36Sopenharmony_ci	}
192462306a36Sopenharmony_ci	*data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index];
192562306a36Sopenharmony_ci	return sizeof(*data);
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_cistatic struct hwrng zcrypt_rng_dev = {
192962306a36Sopenharmony_ci	.name		= "zcrypt",
193062306a36Sopenharmony_ci	.data_read	= zcrypt_rng_data_read,
193162306a36Sopenharmony_ci	.quality	= 990,
193262306a36Sopenharmony_ci};
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ciint zcrypt_rng_device_add(void)
193562306a36Sopenharmony_ci{
193662306a36Sopenharmony_ci	int rc = 0;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	mutex_lock(&zcrypt_rng_mutex);
193962306a36Sopenharmony_ci	if (zcrypt_rng_device_count == 0) {
194062306a36Sopenharmony_ci		zcrypt_rng_buffer = (u32 *)get_zeroed_page(GFP_KERNEL);
194162306a36Sopenharmony_ci		if (!zcrypt_rng_buffer) {
194262306a36Sopenharmony_ci			rc = -ENOMEM;
194362306a36Sopenharmony_ci			goto out;
194462306a36Sopenharmony_ci		}
194562306a36Sopenharmony_ci		zcrypt_rng_buffer_index = 0;
194662306a36Sopenharmony_ci		rc = hwrng_register(&zcrypt_rng_dev);
194762306a36Sopenharmony_ci		if (rc)
194862306a36Sopenharmony_ci			goto out_free;
194962306a36Sopenharmony_ci		zcrypt_rng_device_count = 1;
195062306a36Sopenharmony_ci	} else {
195162306a36Sopenharmony_ci		zcrypt_rng_device_count++;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci	mutex_unlock(&zcrypt_rng_mutex);
195462306a36Sopenharmony_ci	return 0;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ciout_free:
195762306a36Sopenharmony_ci	free_page((unsigned long)zcrypt_rng_buffer);
195862306a36Sopenharmony_ciout:
195962306a36Sopenharmony_ci	mutex_unlock(&zcrypt_rng_mutex);
196062306a36Sopenharmony_ci	return rc;
196162306a36Sopenharmony_ci}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_civoid zcrypt_rng_device_remove(void)
196462306a36Sopenharmony_ci{
196562306a36Sopenharmony_ci	mutex_lock(&zcrypt_rng_mutex);
196662306a36Sopenharmony_ci	zcrypt_rng_device_count--;
196762306a36Sopenharmony_ci	if (zcrypt_rng_device_count == 0) {
196862306a36Sopenharmony_ci		hwrng_unregister(&zcrypt_rng_dev);
196962306a36Sopenharmony_ci		free_page((unsigned long)zcrypt_rng_buffer);
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci	mutex_unlock(&zcrypt_rng_mutex);
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci/*
197562306a36Sopenharmony_ci * Wait until the zcrypt api is operational.
197662306a36Sopenharmony_ci * The AP bus scan and the binding of ap devices to device drivers is
197762306a36Sopenharmony_ci * an asynchronous job. This function waits until these initial jobs
197862306a36Sopenharmony_ci * are done and so the zcrypt api should be ready to serve crypto
197962306a36Sopenharmony_ci * requests - if there are resources available. The function uses an
198062306a36Sopenharmony_ci * internal timeout of 60s. The very first caller will either wait for
198162306a36Sopenharmony_ci * ap bus bindings complete or the timeout happens. This state will be
198262306a36Sopenharmony_ci * remembered for further callers which will only be blocked until a
198362306a36Sopenharmony_ci * decision is made (timeout or bindings complete).
198462306a36Sopenharmony_ci * On timeout -ETIME is returned, on success the return value is 0.
198562306a36Sopenharmony_ci */
198662306a36Sopenharmony_ciint zcrypt_wait_api_operational(void)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	static DEFINE_MUTEX(zcrypt_wait_api_lock);
198962306a36Sopenharmony_ci	static int zcrypt_wait_api_state;
199062306a36Sopenharmony_ci	int rc;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	rc = mutex_lock_interruptible(&zcrypt_wait_api_lock);
199362306a36Sopenharmony_ci	if (rc)
199462306a36Sopenharmony_ci		return rc;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	switch (zcrypt_wait_api_state) {
199762306a36Sopenharmony_ci	case 0:
199862306a36Sopenharmony_ci		/* initial state, invoke wait for the ap bus complete */
199962306a36Sopenharmony_ci		rc = ap_wait_init_apqn_bindings_complete(
200062306a36Sopenharmony_ci			msecs_to_jiffies(60 * 1000));
200162306a36Sopenharmony_ci		switch (rc) {
200262306a36Sopenharmony_ci		case 0:
200362306a36Sopenharmony_ci			/* ap bus bindings are complete */
200462306a36Sopenharmony_ci			zcrypt_wait_api_state = 1;
200562306a36Sopenharmony_ci			break;
200662306a36Sopenharmony_ci		case -EINTR:
200762306a36Sopenharmony_ci			/* interrupted, go back to caller */
200862306a36Sopenharmony_ci			break;
200962306a36Sopenharmony_ci		case -ETIME:
201062306a36Sopenharmony_ci			/* timeout */
201162306a36Sopenharmony_ci			ZCRYPT_DBF_WARN("%s ap_wait_init_apqn_bindings_complete()=ETIME\n",
201262306a36Sopenharmony_ci					__func__);
201362306a36Sopenharmony_ci			zcrypt_wait_api_state = -ETIME;
201462306a36Sopenharmony_ci			break;
201562306a36Sopenharmony_ci		default:
201662306a36Sopenharmony_ci			/* other failure */
201762306a36Sopenharmony_ci			ZCRYPT_DBF_DBG("%s ap_wait_init_apqn_bindings_complete()=%d\n",
201862306a36Sopenharmony_ci				       __func__, rc);
201962306a36Sopenharmony_ci			break;
202062306a36Sopenharmony_ci		}
202162306a36Sopenharmony_ci		break;
202262306a36Sopenharmony_ci	case 1:
202362306a36Sopenharmony_ci		/* a previous caller already found ap bus bindings complete */
202462306a36Sopenharmony_ci		rc = 0;
202562306a36Sopenharmony_ci		break;
202662306a36Sopenharmony_ci	default:
202762306a36Sopenharmony_ci		/* a previous caller had timeout or other failure */
202862306a36Sopenharmony_ci		rc = zcrypt_wait_api_state;
202962306a36Sopenharmony_ci		break;
203062306a36Sopenharmony_ci	}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	mutex_unlock(&zcrypt_wait_api_lock);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	return rc;
203562306a36Sopenharmony_ci}
203662306a36Sopenharmony_ciEXPORT_SYMBOL(zcrypt_wait_api_operational);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ciint __init zcrypt_debug_init(void)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	zcrypt_dbf_info = debug_register("zcrypt", 2, 1,
204162306a36Sopenharmony_ci					 DBF_MAX_SPRINTF_ARGS * sizeof(long));
204262306a36Sopenharmony_ci	debug_register_view(zcrypt_dbf_info, &debug_sprintf_view);
204362306a36Sopenharmony_ci	debug_set_level(zcrypt_dbf_info, DBF_ERR);
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	return 0;
204662306a36Sopenharmony_ci}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_civoid zcrypt_debug_exit(void)
204962306a36Sopenharmony_ci{
205062306a36Sopenharmony_ci	debug_unregister(zcrypt_dbf_info);
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_cistatic int __init zcdn_init(void)
205462306a36Sopenharmony_ci{
205562306a36Sopenharmony_ci	int rc;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* create a new class 'zcrypt' */
205862306a36Sopenharmony_ci	zcrypt_class = class_create(ZCRYPT_NAME);
205962306a36Sopenharmony_ci	if (IS_ERR(zcrypt_class)) {
206062306a36Sopenharmony_ci		rc = PTR_ERR(zcrypt_class);
206162306a36Sopenharmony_ci		goto out_class_create_failed;
206262306a36Sopenharmony_ci	}
206362306a36Sopenharmony_ci	zcrypt_class->dev_release = zcdn_device_release;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	/* alloc device minor range */
206662306a36Sopenharmony_ci	rc = alloc_chrdev_region(&zcrypt_devt,
206762306a36Sopenharmony_ci				 0, ZCRYPT_MAX_MINOR_NODES,
206862306a36Sopenharmony_ci				 ZCRYPT_NAME);
206962306a36Sopenharmony_ci	if (rc)
207062306a36Sopenharmony_ci		goto out_alloc_chrdev_failed;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	cdev_init(&zcrypt_cdev, &zcrypt_fops);
207362306a36Sopenharmony_ci	zcrypt_cdev.owner = THIS_MODULE;
207462306a36Sopenharmony_ci	rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
207562306a36Sopenharmony_ci	if (rc)
207662306a36Sopenharmony_ci		goto out_cdev_add_failed;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	/* need some class specific sysfs attributes */
207962306a36Sopenharmony_ci	rc = class_create_file(zcrypt_class, &class_attr_zcdn_create);
208062306a36Sopenharmony_ci	if (rc)
208162306a36Sopenharmony_ci		goto out_class_create_file_1_failed;
208262306a36Sopenharmony_ci	rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy);
208362306a36Sopenharmony_ci	if (rc)
208462306a36Sopenharmony_ci		goto out_class_create_file_2_failed;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	return 0;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ciout_class_create_file_2_failed:
208962306a36Sopenharmony_ci	class_remove_file(zcrypt_class, &class_attr_zcdn_create);
209062306a36Sopenharmony_ciout_class_create_file_1_failed:
209162306a36Sopenharmony_ci	cdev_del(&zcrypt_cdev);
209262306a36Sopenharmony_ciout_cdev_add_failed:
209362306a36Sopenharmony_ci	unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
209462306a36Sopenharmony_ciout_alloc_chrdev_failed:
209562306a36Sopenharmony_ci	class_destroy(zcrypt_class);
209662306a36Sopenharmony_ciout_class_create_failed:
209762306a36Sopenharmony_ci	return rc;
209862306a36Sopenharmony_ci}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_cistatic void zcdn_exit(void)
210162306a36Sopenharmony_ci{
210262306a36Sopenharmony_ci	class_remove_file(zcrypt_class, &class_attr_zcdn_create);
210362306a36Sopenharmony_ci	class_remove_file(zcrypt_class, &class_attr_zcdn_destroy);
210462306a36Sopenharmony_ci	zcdn_destroy_all();
210562306a36Sopenharmony_ci	cdev_del(&zcrypt_cdev);
210662306a36Sopenharmony_ci	unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
210762306a36Sopenharmony_ci	class_destroy(zcrypt_class);
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci/*
211162306a36Sopenharmony_ci * zcrypt_api_init(): Module initialization.
211262306a36Sopenharmony_ci *
211362306a36Sopenharmony_ci * The module initialization code.
211462306a36Sopenharmony_ci */
211562306a36Sopenharmony_ciint __init zcrypt_api_init(void)
211662306a36Sopenharmony_ci{
211762306a36Sopenharmony_ci	int rc;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	rc = zcrypt_debug_init();
212062306a36Sopenharmony_ci	if (rc)
212162306a36Sopenharmony_ci		goto out;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	rc = zcdn_init();
212462306a36Sopenharmony_ci	if (rc)
212562306a36Sopenharmony_ci		goto out;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	/* Register the request sprayer. */
212862306a36Sopenharmony_ci	rc = misc_register(&zcrypt_misc_device);
212962306a36Sopenharmony_ci	if (rc < 0)
213062306a36Sopenharmony_ci		goto out_misc_register_failed;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	zcrypt_msgtype6_init();
213362306a36Sopenharmony_ci	zcrypt_msgtype50_init();
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	return 0;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ciout_misc_register_failed:
213862306a36Sopenharmony_ci	zcdn_exit();
213962306a36Sopenharmony_ci	zcrypt_debug_exit();
214062306a36Sopenharmony_ciout:
214162306a36Sopenharmony_ci	return rc;
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci/*
214562306a36Sopenharmony_ci * zcrypt_api_exit(): Module termination.
214662306a36Sopenharmony_ci *
214762306a36Sopenharmony_ci * The module termination code.
214862306a36Sopenharmony_ci */
214962306a36Sopenharmony_civoid __exit zcrypt_api_exit(void)
215062306a36Sopenharmony_ci{
215162306a36Sopenharmony_ci	zcdn_exit();
215262306a36Sopenharmony_ci	misc_deregister(&zcrypt_misc_device);
215362306a36Sopenharmony_ci	zcrypt_msgtype6_exit();
215462306a36Sopenharmony_ci	zcrypt_msgtype50_exit();
215562306a36Sopenharmony_ci	zcrypt_ccamisc_exit();
215662306a36Sopenharmony_ci	zcrypt_ep11misc_exit();
215762306a36Sopenharmony_ci	zcrypt_debug_exit();
215862306a36Sopenharmony_ci}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_cimodule_init(zcrypt_api_init);
216162306a36Sopenharmony_cimodule_exit(zcrypt_api_exit);
2162