18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2001, 2018 48c2ecf20Sopenharmony_ci * Author(s): Robert Burroughs 58c2ecf20Sopenharmony_ci * Eric Rossman (edrossma@us.ibm.com) 68c2ecf20Sopenharmony_ci * Cornelia Huck <cornelia.huck@de.ibm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) 98c2ecf20Sopenharmony_ci * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> 108c2ecf20Sopenharmony_ci * Ralph Wuerthner <rwuerthn@de.ibm.com> 118c2ecf20Sopenharmony_ci * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> 128c2ecf20Sopenharmony_ci * Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 198c2ecf20Sopenharmony_ci#include <linux/fs.h> 208c2ecf20Sopenharmony_ci#include <linux/compat.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/atomic.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <linux/hw_random.h> 258c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 268c2ecf20Sopenharmony_ci#include <linux/cdev.h> 278c2ecf20Sopenharmony_ci#include <linux/ctype.h> 288c2ecf20Sopenharmony_ci#include <linux/capability.h> 298c2ecf20Sopenharmony_ci#include <asm/debug.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 328c2ecf20Sopenharmony_ci#include <asm/trace/zcrypt.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "zcrypt_api.h" 358c2ecf20Sopenharmony_ci#include "zcrypt_debug.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "zcrypt_msgtype6.h" 388c2ecf20Sopenharmony_ci#include "zcrypt_msgtype50.h" 398c2ecf20Sopenharmony_ci#include "zcrypt_ccamisc.h" 408c2ecf20Sopenharmony_ci#include "zcrypt_ep11misc.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Module description. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ciMODULE_AUTHOR("IBM Corporation"); 468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \ 478c2ecf20Sopenharmony_ci "Copyright IBM Corp. 2001, 2012"); 488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * zcrypt tracepoint functions 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_req); 548c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_rep); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int zcrypt_hwrng_seed = 1; 578c2ecf20Sopenharmony_cimodule_param_named(hwrng_seed, zcrypt_hwrng_seed, int, 0440); 588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(zcrypt_list_lock); 618c2ecf20Sopenharmony_ciLIST_HEAD(zcrypt_card_list); 628c2ecf20Sopenharmony_ciint zcrypt_device_count; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic atomic_t zcrypt_open_count = ATOMIC_INIT(0); 658c2ecf20Sopenharmony_cistatic atomic_t zcrypt_rescan_count = ATOMIC_INIT(0); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciatomic_t zcrypt_rescan_req = ATOMIC_INIT(0); 688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_rescan_req); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic LIST_HEAD(zcrypt_ops_list); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Zcrypt related debug feature stuff. */ 738c2ecf20Sopenharmony_cidebug_info_t *zcrypt_dbf_info; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/** 768c2ecf20Sopenharmony_ci * Process a rescan of the transport layer. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Returns 1, if the rescan has been processed, otherwise 0. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic inline int zcrypt_process_rescan(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci if (atomic_read(&zcrypt_rescan_req)) { 838c2ecf20Sopenharmony_ci atomic_set(&zcrypt_rescan_req, 0); 848c2ecf20Sopenharmony_ci atomic_inc(&zcrypt_rescan_count); 858c2ecf20Sopenharmony_ci ap_bus_force_rescan(); 868c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_INFO, "rescan count=%07d\n", 878c2ecf20Sopenharmony_ci atomic_inc_return(&zcrypt_rescan_count)); 888c2ecf20Sopenharmony_ci return 1; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_civoid zcrypt_msgtype_register(struct zcrypt_ops *zops) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci list_add_tail(&zops->list, &zcrypt_ops_list); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_civoid zcrypt_msgtype_unregister(struct zcrypt_ops *zops) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci list_del_init(&zops->list); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct zcrypt_ops *zops; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci list_for_each_entry(zops, &zcrypt_ops_list, list) 1088c2ecf20Sopenharmony_ci if ((zops->variant == variant) && 1098c2ecf20Sopenharmony_ci (!strncmp(zops->name, name, sizeof(zops->name)))) 1108c2ecf20Sopenharmony_ci return zops; 1118c2ecf20Sopenharmony_ci return NULL; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_msgtype); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * Multi device nodes extension functions. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistruct zcdn_device; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct class *zcrypt_class; 1248c2ecf20Sopenharmony_cistatic dev_t zcrypt_devt; 1258c2ecf20Sopenharmony_cistatic struct cdev zcrypt_cdev; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct zcdn_device { 1288c2ecf20Sopenharmony_ci struct device device; 1298c2ecf20Sopenharmony_ci struct ap_perms perms; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define ZCDN_MAX_NAME 32 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int zcdn_create(const char *name); 1378c2ecf20Sopenharmony_cistatic int zcdn_destroy(const char *name); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * Find zcdn device by name. 1418c2ecf20Sopenharmony_ci * Returns reference to the zcdn device which needs to be released 1428c2ecf20Sopenharmony_ci * with put_device() after use. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistatic inline struct zcdn_device *find_zcdndev_by_name(const char *name) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct device *dev = class_find_device_by_name(zcrypt_class, name); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return dev ? to_zcdn_dev(dev) : NULL; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* 1528c2ecf20Sopenharmony_ci * Find zcdn device by devt value. 1538c2ecf20Sopenharmony_ci * Returns reference to the zcdn device which needs to be released 1548c2ecf20Sopenharmony_ci * with put_device() after use. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_cistatic inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct device *dev = class_find_device_by_devt(zcrypt_class, devt); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return dev ? to_zcdn_dev(dev) : NULL; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic ssize_t ioctlmask_show(struct device *dev, 1648c2ecf20Sopenharmony_ci struct device_attribute *attr, 1658c2ecf20Sopenharmony_ci char *buf) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int i, rc; 1688c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 1718c2ecf20Sopenharmony_ci return -ERESTARTSYS; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci buf[0] = '0'; 1748c2ecf20Sopenharmony_ci buf[1] = 'x'; 1758c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++) 1768c2ecf20Sopenharmony_ci snprintf(buf + 2 + 2 * i * sizeof(long), 1778c2ecf20Sopenharmony_ci PAGE_SIZE - 2 - 2 * i * sizeof(long), 1788c2ecf20Sopenharmony_ci "%016lx", zcdndev->perms.ioctlm[i]); 1798c2ecf20Sopenharmony_ci buf[2 + 2 * i * sizeof(long)] = '\n'; 1808c2ecf20Sopenharmony_ci buf[2 + 2 * i * sizeof(long) + 1] = '\0'; 1818c2ecf20Sopenharmony_ci rc = 2 + 2 * i * sizeof(long) + 1; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return rc; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic ssize_t ioctlmask_store(struct device *dev, 1898c2ecf20Sopenharmony_ci struct device_attribute *attr, 1908c2ecf20Sopenharmony_ci const char *buf, size_t count) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci int rc; 1938c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm, 1968c2ecf20Sopenharmony_ci AP_IOCTLS, &ap_perms_mutex); 1978c2ecf20Sopenharmony_ci if (rc) 1988c2ecf20Sopenharmony_ci return rc; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return count; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(ioctlmask); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic ssize_t apmask_show(struct device *dev, 2068c2ecf20Sopenharmony_ci struct device_attribute *attr, 2078c2ecf20Sopenharmony_ci char *buf) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci int i, rc; 2108c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 2138c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci buf[0] = '0'; 2168c2ecf20Sopenharmony_ci buf[1] = 'x'; 2178c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++) 2188c2ecf20Sopenharmony_ci snprintf(buf + 2 + 2 * i * sizeof(long), 2198c2ecf20Sopenharmony_ci PAGE_SIZE - 2 - 2 * i * sizeof(long), 2208c2ecf20Sopenharmony_ci "%016lx", zcdndev->perms.apm[i]); 2218c2ecf20Sopenharmony_ci buf[2 + 2 * i * sizeof(long)] = '\n'; 2228c2ecf20Sopenharmony_ci buf[2 + 2 * i * sizeof(long) + 1] = '\0'; 2238c2ecf20Sopenharmony_ci rc = 2 + 2 * i * sizeof(long) + 1; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return rc; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic ssize_t apmask_store(struct device *dev, 2318c2ecf20Sopenharmony_ci struct device_attribute *attr, 2328c2ecf20Sopenharmony_ci const char *buf, size_t count) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci int rc; 2358c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci rc = ap_parse_mask_str(buf, zcdndev->perms.apm, 2388c2ecf20Sopenharmony_ci AP_DEVICES, &ap_perms_mutex); 2398c2ecf20Sopenharmony_ci if (rc) 2408c2ecf20Sopenharmony_ci return rc; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return count; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(apmask); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic ssize_t aqmask_show(struct device *dev, 2488c2ecf20Sopenharmony_ci struct device_attribute *attr, 2498c2ecf20Sopenharmony_ci char *buf) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int i, rc; 2528c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 2558c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci buf[0] = '0'; 2588c2ecf20Sopenharmony_ci buf[1] = 'x'; 2598c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++) 2608c2ecf20Sopenharmony_ci snprintf(buf + 2 + 2 * i * sizeof(long), 2618c2ecf20Sopenharmony_ci PAGE_SIZE - 2 - 2 * i * sizeof(long), 2628c2ecf20Sopenharmony_ci "%016lx", zcdndev->perms.aqm[i]); 2638c2ecf20Sopenharmony_ci buf[2 + 2 * i * sizeof(long)] = '\n'; 2648c2ecf20Sopenharmony_ci buf[2 + 2 * i * sizeof(long) + 1] = '\0'; 2658c2ecf20Sopenharmony_ci rc = 2 + 2 * i * sizeof(long) + 1; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return rc; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic ssize_t aqmask_store(struct device *dev, 2738c2ecf20Sopenharmony_ci struct device_attribute *attr, 2748c2ecf20Sopenharmony_ci const char *buf, size_t count) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int rc; 2778c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci rc = ap_parse_mask_str(buf, zcdndev->perms.aqm, 2808c2ecf20Sopenharmony_ci AP_DOMAINS, &ap_perms_mutex); 2818c2ecf20Sopenharmony_ci if (rc) 2828c2ecf20Sopenharmony_ci return rc; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return count; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(aqmask); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic struct attribute *zcdn_dev_attrs[] = { 2908c2ecf20Sopenharmony_ci &dev_attr_ioctlmask.attr, 2918c2ecf20Sopenharmony_ci &dev_attr_apmask.attr, 2928c2ecf20Sopenharmony_ci &dev_attr_aqmask.attr, 2938c2ecf20Sopenharmony_ci NULL 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic struct attribute_group zcdn_dev_attr_group = { 2978c2ecf20Sopenharmony_ci .attrs = zcdn_dev_attrs 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic const struct attribute_group *zcdn_dev_attr_groups[] = { 3018c2ecf20Sopenharmony_ci &zcdn_dev_attr_group, 3028c2ecf20Sopenharmony_ci NULL 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic ssize_t zcdn_create_store(struct class *class, 3068c2ecf20Sopenharmony_ci struct class_attribute *attr, 3078c2ecf20Sopenharmony_ci const char *buf, size_t count) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci char name[ZCDN_MAX_NAME]; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci strncpy(name, skip_spaces(buf), sizeof(name)); 3138c2ecf20Sopenharmony_ci name[sizeof(name) - 1] = '\0'; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci rc = zcdn_create(strim(name)); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return rc ? rc : count; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic const struct class_attribute class_attr_zcdn_create = 3218c2ecf20Sopenharmony_ci __ATTR(create, 0600, NULL, zcdn_create_store); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic ssize_t zcdn_destroy_store(struct class *class, 3248c2ecf20Sopenharmony_ci struct class_attribute *attr, 3258c2ecf20Sopenharmony_ci const char *buf, size_t count) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci int rc; 3288c2ecf20Sopenharmony_ci char name[ZCDN_MAX_NAME]; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci strncpy(name, skip_spaces(buf), sizeof(name)); 3318c2ecf20Sopenharmony_ci name[sizeof(name) - 1] = '\0'; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci rc = zcdn_destroy(strim(name)); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return rc ? rc : count; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic const struct class_attribute class_attr_zcdn_destroy = 3398c2ecf20Sopenharmony_ci __ATTR(destroy, 0600, NULL, zcdn_destroy_store); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void zcdn_device_release(struct device *dev) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev = to_zcdn_dev(dev); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n", 3468c2ecf20Sopenharmony_ci MAJOR(dev->devt), MINOR(dev->devt)); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci kfree(zcdndev); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int zcdn_create(const char *name) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci dev_t devt; 3548c2ecf20Sopenharmony_ci int i, rc = 0; 3558c2ecf20Sopenharmony_ci char nodename[ZCDN_MAX_NAME]; 3568c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 3598c2ecf20Sopenharmony_ci return -ERESTARTSYS; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* check if device node with this name already exists */ 3628c2ecf20Sopenharmony_ci if (name[0]) { 3638c2ecf20Sopenharmony_ci zcdndev = find_zcdndev_by_name(name); 3648c2ecf20Sopenharmony_ci if (zcdndev) { 3658c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 3668c2ecf20Sopenharmony_ci rc = -EEXIST; 3678c2ecf20Sopenharmony_ci goto unlockout; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* find an unused minor number */ 3728c2ecf20Sopenharmony_ci for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) { 3738c2ecf20Sopenharmony_ci devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i); 3748c2ecf20Sopenharmony_ci zcdndev = find_zcdndev_by_devt(devt); 3758c2ecf20Sopenharmony_ci if (zcdndev) 3768c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 3778c2ecf20Sopenharmony_ci else 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci if (i == ZCRYPT_MAX_MINOR_NODES) { 3818c2ecf20Sopenharmony_ci rc = -ENOSPC; 3828c2ecf20Sopenharmony_ci goto unlockout; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* alloc and prepare a new zcdn device */ 3868c2ecf20Sopenharmony_ci zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL); 3878c2ecf20Sopenharmony_ci if (!zcdndev) { 3888c2ecf20Sopenharmony_ci rc = -ENOMEM; 3898c2ecf20Sopenharmony_ci goto unlockout; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci zcdndev->device.release = zcdn_device_release; 3928c2ecf20Sopenharmony_ci zcdndev->device.class = zcrypt_class; 3938c2ecf20Sopenharmony_ci zcdndev->device.devt = devt; 3948c2ecf20Sopenharmony_ci zcdndev->device.groups = zcdn_dev_attr_groups; 3958c2ecf20Sopenharmony_ci if (name[0]) 3968c2ecf20Sopenharmony_ci strncpy(nodename, name, sizeof(nodename)); 3978c2ecf20Sopenharmony_ci else 3988c2ecf20Sopenharmony_ci snprintf(nodename, sizeof(nodename), 3998c2ecf20Sopenharmony_ci ZCRYPT_NAME "_%d", (int) MINOR(devt)); 4008c2ecf20Sopenharmony_ci nodename[sizeof(nodename)-1] = '\0'; 4018c2ecf20Sopenharmony_ci if (dev_set_name(&zcdndev->device, nodename)) { 4028c2ecf20Sopenharmony_ci kfree(zcdndev); 4038c2ecf20Sopenharmony_ci rc = -EINVAL; 4048c2ecf20Sopenharmony_ci goto unlockout; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci rc = device_register(&zcdndev->device); 4078c2ecf20Sopenharmony_ci if (rc) { 4088c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 4098c2ecf20Sopenharmony_ci goto unlockout; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n", 4138c2ecf20Sopenharmony_ci MAJOR(devt), MINOR(devt)); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ciunlockout: 4168c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 4178c2ecf20Sopenharmony_ci return rc; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int zcdn_destroy(const char *name) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci int rc = 0; 4238c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 4268c2ecf20Sopenharmony_ci return -ERESTARTSYS; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* try to find this zcdn device */ 4298c2ecf20Sopenharmony_ci zcdndev = find_zcdndev_by_name(name); 4308c2ecf20Sopenharmony_ci if (!zcdndev) { 4318c2ecf20Sopenharmony_ci rc = -ENOENT; 4328c2ecf20Sopenharmony_ci goto unlockout; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* 4368c2ecf20Sopenharmony_ci * The zcdn device is not hard destroyed. It is subject to 4378c2ecf20Sopenharmony_ci * reference counting and thus just needs to be unregistered. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 4408c2ecf20Sopenharmony_ci device_unregister(&zcdndev->device); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ciunlockout: 4438c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 4448c2ecf20Sopenharmony_ci return rc; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void zcdn_destroy_all(void) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci int i; 4508c2ecf20Sopenharmony_ci dev_t devt; 4518c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci mutex_lock(&ap_perms_mutex); 4548c2ecf20Sopenharmony_ci for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) { 4558c2ecf20Sopenharmony_ci devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i); 4568c2ecf20Sopenharmony_ci zcdndev = find_zcdndev_by_devt(devt); 4578c2ecf20Sopenharmony_ci if (zcdndev) { 4588c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 4598c2ecf20Sopenharmony_ci device_unregister(&zcdndev->device); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#endif 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/** 4688c2ecf20Sopenharmony_ci * zcrypt_read (): Not supported beyond zcrypt 1.3.1. 4698c2ecf20Sopenharmony_ci * 4708c2ecf20Sopenharmony_ci * This function is not supported beyond zcrypt 1.3.1. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistatic ssize_t zcrypt_read(struct file *filp, char __user *buf, 4738c2ecf20Sopenharmony_ci size_t count, loff_t *f_pos) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci return -EPERM; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/** 4798c2ecf20Sopenharmony_ci * zcrypt_write(): Not allowed. 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * Write is is not allowed 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_cistatic ssize_t zcrypt_write(struct file *filp, const char __user *buf, 4848c2ecf20Sopenharmony_ci size_t count, loff_t *f_pos) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci return -EPERM; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/** 4908c2ecf20Sopenharmony_ci * zcrypt_open(): Count number of users. 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * Device open function to count number of users. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_cistatic int zcrypt_open(struct inode *inode, struct file *filp) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct ap_perms *perms = &ap_perms; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 4998c2ecf20Sopenharmony_ci if (filp->f_inode->i_cdev == &zcrypt_cdev) { 5008c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 5038c2ecf20Sopenharmony_ci return -ERESTARTSYS; 5048c2ecf20Sopenharmony_ci zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev); 5058c2ecf20Sopenharmony_ci /* find returns a reference, no get_device() needed */ 5068c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 5078c2ecf20Sopenharmony_ci if (zcdndev) 5088c2ecf20Sopenharmony_ci perms = &zcdndev->perms; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci#endif 5118c2ecf20Sopenharmony_ci filp->private_data = (void *) perms; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci atomic_inc(&zcrypt_open_count); 5148c2ecf20Sopenharmony_ci return stream_open(inode, filp); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/** 5188c2ecf20Sopenharmony_ci * zcrypt_release(): Count number of users. 5198c2ecf20Sopenharmony_ci * 5208c2ecf20Sopenharmony_ci * Device close function to count number of users. 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_cistatic int zcrypt_release(struct inode *inode, struct file *filp) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 5258c2ecf20Sopenharmony_ci if (filp->f_inode->i_cdev == &zcrypt_cdev) { 5268c2ecf20Sopenharmony_ci struct zcdn_device *zcdndev; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci mutex_lock(&ap_perms_mutex); 5298c2ecf20Sopenharmony_ci zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev); 5308c2ecf20Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 5318c2ecf20Sopenharmony_ci if (zcdndev) { 5328c2ecf20Sopenharmony_ci /* 2 puts here: one for find, one for open */ 5338c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 5348c2ecf20Sopenharmony_ci put_device(&zcdndev->device); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci#endif 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci atomic_dec(&zcrypt_open_count); 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic inline int zcrypt_check_ioctl(struct ap_perms *perms, 5448c2ecf20Sopenharmony_ci unsigned int cmd) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int rc = -EPERM; 5478c2ecf20Sopenharmony_ci int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) { 5508c2ecf20Sopenharmony_ci if (test_bit_inv(ioctlnr, perms->ioctlm)) 5518c2ecf20Sopenharmony_ci rc = 0; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (rc) 5558c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_WARN, 5568c2ecf20Sopenharmony_ci "ioctl check failed: ioctlnr=0x%04x rc=%d\n", 5578c2ecf20Sopenharmony_ci ioctlnr, rc); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return rc; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic inline bool zcrypt_check_card(struct ap_perms *perms, int card) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci return test_bit_inv(card, perms->apm) ? true : false; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic inline bool zcrypt_check_queue(struct ap_perms *perms, int queue) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci return test_bit_inv(queue, perms->aqm) ? true : false; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc, 5738c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, 5748c2ecf20Sopenharmony_ci struct module **pmod, 5758c2ecf20Sopenharmony_ci unsigned int weight) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci if (!zq || !try_module_get(zq->queue->ap_dev.drv->driver.owner)) 5788c2ecf20Sopenharmony_ci return NULL; 5798c2ecf20Sopenharmony_ci zcrypt_queue_get(zq); 5808c2ecf20Sopenharmony_ci get_device(&zq->queue->ap_dev.device); 5818c2ecf20Sopenharmony_ci atomic_add(weight, &zc->load); 5828c2ecf20Sopenharmony_ci atomic_add(weight, &zq->load); 5838c2ecf20Sopenharmony_ci zq->request_count++; 5848c2ecf20Sopenharmony_ci *pmod = zq->queue->ap_dev.drv->driver.owner; 5858c2ecf20Sopenharmony_ci return zq; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic inline void zcrypt_drop_queue(struct zcrypt_card *zc, 5898c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, 5908c2ecf20Sopenharmony_ci struct module *mod, 5918c2ecf20Sopenharmony_ci unsigned int weight) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci zq->request_count--; 5948c2ecf20Sopenharmony_ci atomic_sub(weight, &zc->load); 5958c2ecf20Sopenharmony_ci atomic_sub(weight, &zq->load); 5968c2ecf20Sopenharmony_ci put_device(&zq->queue->ap_dev.device); 5978c2ecf20Sopenharmony_ci zcrypt_queue_put(zq); 5988c2ecf20Sopenharmony_ci module_put(mod); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic inline bool zcrypt_card_compare(struct zcrypt_card *zc, 6028c2ecf20Sopenharmony_ci struct zcrypt_card *pref_zc, 6038c2ecf20Sopenharmony_ci unsigned int weight, 6048c2ecf20Sopenharmony_ci unsigned int pref_weight) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci if (!pref_zc) 6078c2ecf20Sopenharmony_ci return true; 6088c2ecf20Sopenharmony_ci weight += atomic_read(&zc->load); 6098c2ecf20Sopenharmony_ci pref_weight += atomic_read(&pref_zc->load); 6108c2ecf20Sopenharmony_ci if (weight == pref_weight) 6118c2ecf20Sopenharmony_ci return atomic64_read(&zc->card->total_request_count) < 6128c2ecf20Sopenharmony_ci atomic64_read(&pref_zc->card->total_request_count); 6138c2ecf20Sopenharmony_ci return weight < pref_weight; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, 6178c2ecf20Sopenharmony_ci struct zcrypt_queue *pref_zq, 6188c2ecf20Sopenharmony_ci unsigned int weight, 6198c2ecf20Sopenharmony_ci unsigned int pref_weight) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci if (!pref_zq) 6228c2ecf20Sopenharmony_ci return true; 6238c2ecf20Sopenharmony_ci weight += atomic_read(&zq->load); 6248c2ecf20Sopenharmony_ci pref_weight += atomic_read(&pref_zq->load); 6258c2ecf20Sopenharmony_ci if (weight == pref_weight) 6268c2ecf20Sopenharmony_ci return zq->queue->total_request_count < 6278c2ecf20Sopenharmony_ci pref_zq->queue->total_request_count; 6288c2ecf20Sopenharmony_ci return weight < pref_weight; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/* 6328c2ecf20Sopenharmony_ci * zcrypt ioctls. 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_cistatic long zcrypt_rsa_modexpo(struct ap_perms *perms, 6358c2ecf20Sopenharmony_ci struct zcrypt_track *tr, 6368c2ecf20Sopenharmony_ci struct ica_rsa_modexpo *mex) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct zcrypt_card *zc, *pref_zc; 6398c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, *pref_zq; 6408c2ecf20Sopenharmony_ci struct ap_message ap_msg; 6418c2ecf20Sopenharmony_ci unsigned int wgt = 0, pref_wgt = 0; 6428c2ecf20Sopenharmony_ci unsigned int func_code; 6438c2ecf20Sopenharmony_ci int cpen, qpen, qid = 0, rc = -ENODEV; 6448c2ecf20Sopenharmony_ci struct module *mod; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ap_init_message(&ap_msg); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 6518c2ecf20Sopenharmony_ci if (tr && tr->fi.cmd) 6528c2ecf20Sopenharmony_ci ap_msg.fi.cmd = tr->fi.cmd; 6538c2ecf20Sopenharmony_ci#endif 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (mex->outputdatalength < mex->inputdatalength) { 6568c2ecf20Sopenharmony_ci func_code = 0; 6578c2ecf20Sopenharmony_ci rc = -EINVAL; 6588c2ecf20Sopenharmony_ci goto out; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * As long as outputdatalength is big enough, we can set the 6638c2ecf20Sopenharmony_ci * outputdatalength equal to the inputdatalength, since that is the 6648c2ecf20Sopenharmony_ci * number of bytes we will copy in any case 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci mex->outputdatalength = mex->inputdatalength; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci rc = get_rsa_modex_fc(mex, &func_code); 6698c2ecf20Sopenharmony_ci if (rc) 6708c2ecf20Sopenharmony_ci goto out; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci pref_zc = NULL; 6738c2ecf20Sopenharmony_ci pref_zq = NULL; 6748c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 6758c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 6768c2ecf20Sopenharmony_ci /* Check for useable accelarator or CCA card */ 6778c2ecf20Sopenharmony_ci if (!zc->online || !zc->card->config || 6788c2ecf20Sopenharmony_ci !(zc->card->functions & 0x18000000)) 6798c2ecf20Sopenharmony_ci continue; 6808c2ecf20Sopenharmony_ci /* Check for size limits */ 6818c2ecf20Sopenharmony_ci if (zc->min_mod_size > mex->inputdatalength || 6828c2ecf20Sopenharmony_ci zc->max_mod_size < mex->inputdatalength) 6838c2ecf20Sopenharmony_ci continue; 6848c2ecf20Sopenharmony_ci /* check if device node has admission for this card */ 6858c2ecf20Sopenharmony_ci if (!zcrypt_check_card(perms, zc->card->id)) 6868c2ecf20Sopenharmony_ci continue; 6878c2ecf20Sopenharmony_ci /* get weight index of the card device */ 6888c2ecf20Sopenharmony_ci wgt = zc->speed_rating[func_code]; 6898c2ecf20Sopenharmony_ci /* penalty if this msg was previously sent via this card */ 6908c2ecf20Sopenharmony_ci cpen = (tr && tr->again_counter && tr->last_qid && 6918c2ecf20Sopenharmony_ci AP_QID_CARD(tr->last_qid) == zc->card->id) ? 6928c2ecf20Sopenharmony_ci TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; 6938c2ecf20Sopenharmony_ci if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) 6948c2ecf20Sopenharmony_ci continue; 6958c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 6968c2ecf20Sopenharmony_ci /* check if device is useable and eligible */ 6978c2ecf20Sopenharmony_ci if (!zq->online || !zq->ops->rsa_modexpo || 6988c2ecf20Sopenharmony_ci !zq->queue->config) 6998c2ecf20Sopenharmony_ci continue; 7008c2ecf20Sopenharmony_ci /* check if device node has admission for this queue */ 7018c2ecf20Sopenharmony_ci if (!zcrypt_check_queue(perms, 7028c2ecf20Sopenharmony_ci AP_QID_QUEUE(zq->queue->qid))) 7038c2ecf20Sopenharmony_ci continue; 7048c2ecf20Sopenharmony_ci /* penalty if the msg was previously sent at this qid */ 7058c2ecf20Sopenharmony_ci qpen = (tr && tr->again_counter && tr->last_qid && 7068c2ecf20Sopenharmony_ci tr->last_qid == zq->queue->qid) ? 7078c2ecf20Sopenharmony_ci TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; 7088c2ecf20Sopenharmony_ci if (!zcrypt_queue_compare(zq, pref_zq, 7098c2ecf20Sopenharmony_ci wgt + cpen + qpen, pref_wgt)) 7108c2ecf20Sopenharmony_ci continue; 7118c2ecf20Sopenharmony_ci pref_zc = zc; 7128c2ecf20Sopenharmony_ci pref_zq = zq; 7138c2ecf20Sopenharmony_ci pref_wgt = wgt + cpen + qpen; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); 7178c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (!pref_zq) { 7208c2ecf20Sopenharmony_ci rc = -ENODEV; 7218c2ecf20Sopenharmony_ci goto out; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci qid = pref_zq->queue->qid; 7258c2ecf20Sopenharmony_ci rc = pref_zq->ops->rsa_modexpo(pref_zq, mex, &ap_msg); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 7288c2ecf20Sopenharmony_ci zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); 7298c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ciout: 7328c2ecf20Sopenharmony_ci ap_release_message(&ap_msg); 7338c2ecf20Sopenharmony_ci if (tr) { 7348c2ecf20Sopenharmony_ci tr->last_rc = rc; 7358c2ecf20Sopenharmony_ci tr->last_qid = qid; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci trace_s390_zcrypt_rep(mex, func_code, rc, 7388c2ecf20Sopenharmony_ci AP_QID_CARD(qid), AP_QID_QUEUE(qid)); 7398c2ecf20Sopenharmony_ci return rc; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic long zcrypt_rsa_crt(struct ap_perms *perms, 7438c2ecf20Sopenharmony_ci struct zcrypt_track *tr, 7448c2ecf20Sopenharmony_ci struct ica_rsa_modexpo_crt *crt) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct zcrypt_card *zc, *pref_zc; 7478c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, *pref_zq; 7488c2ecf20Sopenharmony_ci struct ap_message ap_msg; 7498c2ecf20Sopenharmony_ci unsigned int wgt = 0, pref_wgt = 0; 7508c2ecf20Sopenharmony_ci unsigned int func_code; 7518c2ecf20Sopenharmony_ci int cpen, qpen, qid = 0, rc = -ENODEV; 7528c2ecf20Sopenharmony_ci struct module *mod; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci trace_s390_zcrypt_req(crt, TP_ICARSACRT); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci ap_init_message(&ap_msg); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 7598c2ecf20Sopenharmony_ci if (tr && tr->fi.cmd) 7608c2ecf20Sopenharmony_ci ap_msg.fi.cmd = tr->fi.cmd; 7618c2ecf20Sopenharmony_ci#endif 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (crt->outputdatalength < crt->inputdatalength) { 7648c2ecf20Sopenharmony_ci func_code = 0; 7658c2ecf20Sopenharmony_ci rc = -EINVAL; 7668c2ecf20Sopenharmony_ci goto out; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* 7708c2ecf20Sopenharmony_ci * As long as outputdatalength is big enough, we can set the 7718c2ecf20Sopenharmony_ci * outputdatalength equal to the inputdatalength, since that is the 7728c2ecf20Sopenharmony_ci * number of bytes we will copy in any case 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci crt->outputdatalength = crt->inputdatalength; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci rc = get_rsa_crt_fc(crt, &func_code); 7778c2ecf20Sopenharmony_ci if (rc) 7788c2ecf20Sopenharmony_ci goto out; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci pref_zc = NULL; 7818c2ecf20Sopenharmony_ci pref_zq = NULL; 7828c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 7838c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 7848c2ecf20Sopenharmony_ci /* Check for useable accelarator or CCA card */ 7858c2ecf20Sopenharmony_ci if (!zc->online || !zc->card->config || 7868c2ecf20Sopenharmony_ci !(zc->card->functions & 0x18000000)) 7878c2ecf20Sopenharmony_ci continue; 7888c2ecf20Sopenharmony_ci /* Check for size limits */ 7898c2ecf20Sopenharmony_ci if (zc->min_mod_size > crt->inputdatalength || 7908c2ecf20Sopenharmony_ci zc->max_mod_size < crt->inputdatalength) 7918c2ecf20Sopenharmony_ci continue; 7928c2ecf20Sopenharmony_ci /* check if device node has admission for this card */ 7938c2ecf20Sopenharmony_ci if (!zcrypt_check_card(perms, zc->card->id)) 7948c2ecf20Sopenharmony_ci continue; 7958c2ecf20Sopenharmony_ci /* get weight index of the card device */ 7968c2ecf20Sopenharmony_ci wgt = zc->speed_rating[func_code]; 7978c2ecf20Sopenharmony_ci /* penalty if this msg was previously sent via this card */ 7988c2ecf20Sopenharmony_ci cpen = (tr && tr->again_counter && tr->last_qid && 7998c2ecf20Sopenharmony_ci AP_QID_CARD(tr->last_qid) == zc->card->id) ? 8008c2ecf20Sopenharmony_ci TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; 8018c2ecf20Sopenharmony_ci if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) 8028c2ecf20Sopenharmony_ci continue; 8038c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 8048c2ecf20Sopenharmony_ci /* check if device is useable and eligible */ 8058c2ecf20Sopenharmony_ci if (!zq->online || !zq->ops->rsa_modexpo_crt || 8068c2ecf20Sopenharmony_ci !zq->queue->config) 8078c2ecf20Sopenharmony_ci continue; 8088c2ecf20Sopenharmony_ci /* check if device node has admission for this queue */ 8098c2ecf20Sopenharmony_ci if (!zcrypt_check_queue(perms, 8108c2ecf20Sopenharmony_ci AP_QID_QUEUE(zq->queue->qid))) 8118c2ecf20Sopenharmony_ci continue; 8128c2ecf20Sopenharmony_ci /* penalty if the msg was previously sent at this qid */ 8138c2ecf20Sopenharmony_ci qpen = (tr && tr->again_counter && tr->last_qid && 8148c2ecf20Sopenharmony_ci tr->last_qid == zq->queue->qid) ? 8158c2ecf20Sopenharmony_ci TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; 8168c2ecf20Sopenharmony_ci if (!zcrypt_queue_compare(zq, pref_zq, 8178c2ecf20Sopenharmony_ci wgt + cpen + qpen, pref_wgt)) 8188c2ecf20Sopenharmony_ci continue; 8198c2ecf20Sopenharmony_ci pref_zc = zc; 8208c2ecf20Sopenharmony_ci pref_zq = zq; 8218c2ecf20Sopenharmony_ci pref_wgt = wgt + cpen + qpen; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); 8258c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (!pref_zq) { 8288c2ecf20Sopenharmony_ci rc = -ENODEV; 8298c2ecf20Sopenharmony_ci goto out; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci qid = pref_zq->queue->qid; 8338c2ecf20Sopenharmony_ci rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt, &ap_msg); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 8368c2ecf20Sopenharmony_ci zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); 8378c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciout: 8408c2ecf20Sopenharmony_ci ap_release_message(&ap_msg); 8418c2ecf20Sopenharmony_ci if (tr) { 8428c2ecf20Sopenharmony_ci tr->last_rc = rc; 8438c2ecf20Sopenharmony_ci tr->last_qid = qid; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci trace_s390_zcrypt_rep(crt, func_code, rc, 8468c2ecf20Sopenharmony_ci AP_QID_CARD(qid), AP_QID_QUEUE(qid)); 8478c2ecf20Sopenharmony_ci return rc; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, 8518c2ecf20Sopenharmony_ci struct zcrypt_track *tr, 8528c2ecf20Sopenharmony_ci struct ica_xcRB *xcRB) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct zcrypt_card *zc, *pref_zc; 8558c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, *pref_zq; 8568c2ecf20Sopenharmony_ci struct ap_message ap_msg; 8578c2ecf20Sopenharmony_ci unsigned int wgt = 0, pref_wgt = 0; 8588c2ecf20Sopenharmony_ci unsigned int func_code; 8598c2ecf20Sopenharmony_ci unsigned short *domain, tdom; 8608c2ecf20Sopenharmony_ci int cpen, qpen, qid = 0, rc = -ENODEV; 8618c2ecf20Sopenharmony_ci struct module *mod; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci xcRB->status = 0; 8668c2ecf20Sopenharmony_ci ap_init_message(&ap_msg); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 8698c2ecf20Sopenharmony_ci if (tr && tr->fi.cmd) 8708c2ecf20Sopenharmony_ci ap_msg.fi.cmd = tr->fi.cmd; 8718c2ecf20Sopenharmony_ci if (tr && tr->fi.action == AP_FI_ACTION_CCA_AGENT_FF) { 8728c2ecf20Sopenharmony_ci ZCRYPT_DBF_WARN("%s fi cmd 0x%04x: forcing invalid agent_ID 'FF'\n", 8738c2ecf20Sopenharmony_ci __func__, tr->fi.cmd); 8748c2ecf20Sopenharmony_ci xcRB->agent_ID = 0x4646; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci#endif 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci rc = get_cprb_fc(userspace, xcRB, &ap_msg, &func_code, &domain); 8798c2ecf20Sopenharmony_ci if (rc) 8808c2ecf20Sopenharmony_ci goto out; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* 8838c2ecf20Sopenharmony_ci * If a valid target domain is set and this domain is NOT a usage 8848c2ecf20Sopenharmony_ci * domain but a control only domain, use the default domain as target. 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_ci tdom = *domain; 8878c2ecf20Sopenharmony_ci if (tdom < AP_DOMAINS && 8888c2ecf20Sopenharmony_ci !ap_test_config_usage_domain(tdom) && 8898c2ecf20Sopenharmony_ci ap_test_config_ctrl_domain(tdom) && 8908c2ecf20Sopenharmony_ci ap_domain_index >= 0) 8918c2ecf20Sopenharmony_ci tdom = ap_domain_index; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci pref_zc = NULL; 8948c2ecf20Sopenharmony_ci pref_zq = NULL; 8958c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 8968c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 8978c2ecf20Sopenharmony_ci /* Check for useable CCA card */ 8988c2ecf20Sopenharmony_ci if (!zc->online || !zc->card->config || 8998c2ecf20Sopenharmony_ci !(zc->card->functions & 0x10000000)) 9008c2ecf20Sopenharmony_ci continue; 9018c2ecf20Sopenharmony_ci /* Check for user selected CCA card */ 9028c2ecf20Sopenharmony_ci if (xcRB->user_defined != AUTOSELECT && 9038c2ecf20Sopenharmony_ci xcRB->user_defined != zc->card->id) 9048c2ecf20Sopenharmony_ci continue; 9058c2ecf20Sopenharmony_ci /* check if device node has admission for this card */ 9068c2ecf20Sopenharmony_ci if (!zcrypt_check_card(perms, zc->card->id)) 9078c2ecf20Sopenharmony_ci continue; 9088c2ecf20Sopenharmony_ci /* get weight index of the card device */ 9098c2ecf20Sopenharmony_ci wgt = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; 9108c2ecf20Sopenharmony_ci /* penalty if this msg was previously sent via this card */ 9118c2ecf20Sopenharmony_ci cpen = (tr && tr->again_counter && tr->last_qid && 9128c2ecf20Sopenharmony_ci AP_QID_CARD(tr->last_qid) == zc->card->id) ? 9138c2ecf20Sopenharmony_ci TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; 9148c2ecf20Sopenharmony_ci if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) 9158c2ecf20Sopenharmony_ci continue; 9168c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 9178c2ecf20Sopenharmony_ci /* check for device useable and eligible */ 9188c2ecf20Sopenharmony_ci if (!zq->online || 9198c2ecf20Sopenharmony_ci !zq->ops->send_cprb || 9208c2ecf20Sopenharmony_ci !zq->queue->config || 9218c2ecf20Sopenharmony_ci (tdom != AUTOSEL_DOM && 9228c2ecf20Sopenharmony_ci tdom != AP_QID_QUEUE(zq->queue->qid))) 9238c2ecf20Sopenharmony_ci continue; 9248c2ecf20Sopenharmony_ci /* check if device node has admission for this queue */ 9258c2ecf20Sopenharmony_ci if (!zcrypt_check_queue(perms, 9268c2ecf20Sopenharmony_ci AP_QID_QUEUE(zq->queue->qid))) 9278c2ecf20Sopenharmony_ci continue; 9288c2ecf20Sopenharmony_ci /* penalty if the msg was previously sent at this qid */ 9298c2ecf20Sopenharmony_ci qpen = (tr && tr->again_counter && tr->last_qid && 9308c2ecf20Sopenharmony_ci tr->last_qid == zq->queue->qid) ? 9318c2ecf20Sopenharmony_ci TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; 9328c2ecf20Sopenharmony_ci if (!zcrypt_queue_compare(zq, pref_zq, 9338c2ecf20Sopenharmony_ci wgt + cpen + qpen, pref_wgt)) 9348c2ecf20Sopenharmony_ci continue; 9358c2ecf20Sopenharmony_ci pref_zc = zc; 9368c2ecf20Sopenharmony_ci pref_zq = zq; 9378c2ecf20Sopenharmony_ci pref_wgt = wgt + cpen + qpen; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); 9418c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (!pref_zq) { 9448c2ecf20Sopenharmony_ci rc = -ENODEV; 9458c2ecf20Sopenharmony_ci goto out; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* in case of auto select, provide the correct domain */ 9498c2ecf20Sopenharmony_ci qid = pref_zq->queue->qid; 9508c2ecf20Sopenharmony_ci if (*domain == AUTOSEL_DOM) 9518c2ecf20Sopenharmony_ci *domain = AP_QID_QUEUE(qid); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 9548c2ecf20Sopenharmony_ci if (tr && tr->fi.action == AP_FI_ACTION_CCA_DOM_INVAL) { 9558c2ecf20Sopenharmony_ci ZCRYPT_DBF_WARN("%s fi cmd 0x%04x: forcing invalid domain\n", 9568c2ecf20Sopenharmony_ci __func__, tr->fi.cmd); 9578c2ecf20Sopenharmony_ci *domain = 99; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci#endif 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcRB, &ap_msg); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 9648c2ecf20Sopenharmony_ci zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); 9658c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ciout: 9688c2ecf20Sopenharmony_ci ap_release_message(&ap_msg); 9698c2ecf20Sopenharmony_ci if (tr) { 9708c2ecf20Sopenharmony_ci tr->last_rc = rc; 9718c2ecf20Sopenharmony_ci tr->last_qid = qid; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci trace_s390_zcrypt_rep(xcRB, func_code, rc, 9748c2ecf20Sopenharmony_ci AP_QID_CARD(qid), AP_QID_QUEUE(qid)); 9758c2ecf20Sopenharmony_ci return rc; 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cilong zcrypt_send_cprb(struct ica_xcRB *xcRB) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci return _zcrypt_send_cprb(false, &ap_perms, NULL, xcRB); 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_send_cprb); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic bool is_desired_ep11_card(unsigned int dev_id, 9858c2ecf20Sopenharmony_ci unsigned short target_num, 9868c2ecf20Sopenharmony_ci struct ep11_target_dev *targets) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci while (target_num-- > 0) { 9898c2ecf20Sopenharmony_ci if (targets->ap_id == dev_id || targets->ap_id == AUTOSEL_AP) 9908c2ecf20Sopenharmony_ci return true; 9918c2ecf20Sopenharmony_ci targets++; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci return false; 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic bool is_desired_ep11_queue(unsigned int dev_qid, 9978c2ecf20Sopenharmony_ci unsigned short target_num, 9988c2ecf20Sopenharmony_ci struct ep11_target_dev *targets) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci int card = AP_QID_CARD(dev_qid), dom = AP_QID_QUEUE(dev_qid); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci while (target_num-- > 0) { 10038c2ecf20Sopenharmony_ci if ((targets->ap_id == card || targets->ap_id == AUTOSEL_AP) && 10048c2ecf20Sopenharmony_ci (targets->dom_id == dom || targets->dom_id == AUTOSEL_DOM)) 10058c2ecf20Sopenharmony_ci return true; 10068c2ecf20Sopenharmony_ci targets++; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci return false; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, 10128c2ecf20Sopenharmony_ci struct zcrypt_track *tr, 10138c2ecf20Sopenharmony_ci struct ep11_urb *xcrb) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct zcrypt_card *zc, *pref_zc; 10168c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, *pref_zq; 10178c2ecf20Sopenharmony_ci struct ep11_target_dev *targets; 10188c2ecf20Sopenharmony_ci unsigned short target_num; 10198c2ecf20Sopenharmony_ci unsigned int wgt = 0, pref_wgt = 0; 10208c2ecf20Sopenharmony_ci unsigned int func_code; 10218c2ecf20Sopenharmony_ci struct ap_message ap_msg; 10228c2ecf20Sopenharmony_ci int cpen, qpen, qid = 0, rc = -ENODEV; 10238c2ecf20Sopenharmony_ci struct module *mod; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci ap_init_message(&ap_msg); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 10308c2ecf20Sopenharmony_ci if (tr && tr->fi.cmd) 10318c2ecf20Sopenharmony_ci ap_msg.fi.cmd = tr->fi.cmd; 10328c2ecf20Sopenharmony_ci#endif 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci target_num = (unsigned short) xcrb->targets_num; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* empty list indicates autoselect (all available targets) */ 10378c2ecf20Sopenharmony_ci targets = NULL; 10388c2ecf20Sopenharmony_ci if (target_num != 0) { 10398c2ecf20Sopenharmony_ci struct ep11_target_dev __user *uptr; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL); 10428c2ecf20Sopenharmony_ci if (!targets) { 10438c2ecf20Sopenharmony_ci func_code = 0; 10448c2ecf20Sopenharmony_ci rc = -ENOMEM; 10458c2ecf20Sopenharmony_ci goto out; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci uptr = (struct ep11_target_dev __force __user *) xcrb->targets; 10498c2ecf20Sopenharmony_ci if (z_copy_from_user(userspace, targets, uptr, 10508c2ecf20Sopenharmony_ci target_num * sizeof(*targets))) { 10518c2ecf20Sopenharmony_ci func_code = 0; 10528c2ecf20Sopenharmony_ci rc = -EFAULT; 10538c2ecf20Sopenharmony_ci goto out_free; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci rc = get_ep11cprb_fc(userspace, xcrb, &ap_msg, &func_code); 10588c2ecf20Sopenharmony_ci if (rc) 10598c2ecf20Sopenharmony_ci goto out_free; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci pref_zc = NULL; 10628c2ecf20Sopenharmony_ci pref_zq = NULL; 10638c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 10648c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 10658c2ecf20Sopenharmony_ci /* Check for useable EP11 card */ 10668c2ecf20Sopenharmony_ci if (!zc->online || !zc->card->config || 10678c2ecf20Sopenharmony_ci !(zc->card->functions & 0x04000000)) 10688c2ecf20Sopenharmony_ci continue; 10698c2ecf20Sopenharmony_ci /* Check for user selected EP11 card */ 10708c2ecf20Sopenharmony_ci if (targets && 10718c2ecf20Sopenharmony_ci !is_desired_ep11_card(zc->card->id, target_num, targets)) 10728c2ecf20Sopenharmony_ci continue; 10738c2ecf20Sopenharmony_ci /* check if device node has admission for this card */ 10748c2ecf20Sopenharmony_ci if (!zcrypt_check_card(perms, zc->card->id)) 10758c2ecf20Sopenharmony_ci continue; 10768c2ecf20Sopenharmony_ci /* get weight index of the card device */ 10778c2ecf20Sopenharmony_ci wgt = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; 10788c2ecf20Sopenharmony_ci /* penalty if this msg was previously sent via this card */ 10798c2ecf20Sopenharmony_ci cpen = (tr && tr->again_counter && tr->last_qid && 10808c2ecf20Sopenharmony_ci AP_QID_CARD(tr->last_qid) == zc->card->id) ? 10818c2ecf20Sopenharmony_ci TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; 10828c2ecf20Sopenharmony_ci if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) 10838c2ecf20Sopenharmony_ci continue; 10848c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 10858c2ecf20Sopenharmony_ci /* check if device is useable and eligible */ 10868c2ecf20Sopenharmony_ci if (!zq->online || 10878c2ecf20Sopenharmony_ci !zq->ops->send_ep11_cprb || 10888c2ecf20Sopenharmony_ci !zq->queue->config || 10898c2ecf20Sopenharmony_ci (targets && 10908c2ecf20Sopenharmony_ci !is_desired_ep11_queue(zq->queue->qid, 10918c2ecf20Sopenharmony_ci target_num, targets))) 10928c2ecf20Sopenharmony_ci continue; 10938c2ecf20Sopenharmony_ci /* check if device node has admission for this queue */ 10948c2ecf20Sopenharmony_ci if (!zcrypt_check_queue(perms, 10958c2ecf20Sopenharmony_ci AP_QID_QUEUE(zq->queue->qid))) 10968c2ecf20Sopenharmony_ci continue; 10978c2ecf20Sopenharmony_ci /* penalty if the msg was previously sent at this qid */ 10988c2ecf20Sopenharmony_ci qpen = (tr && tr->again_counter && tr->last_qid && 10998c2ecf20Sopenharmony_ci tr->last_qid == zq->queue->qid) ? 11008c2ecf20Sopenharmony_ci TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; 11018c2ecf20Sopenharmony_ci if (!zcrypt_queue_compare(zq, pref_zq, 11028c2ecf20Sopenharmony_ci wgt + cpen + qpen, pref_wgt)) 11038c2ecf20Sopenharmony_ci continue; 11048c2ecf20Sopenharmony_ci pref_zc = zc; 11058c2ecf20Sopenharmony_ci pref_zq = zq; 11068c2ecf20Sopenharmony_ci pref_wgt = wgt + cpen + qpen; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); 11108c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (!pref_zq) { 11138c2ecf20Sopenharmony_ci rc = -ENODEV; 11148c2ecf20Sopenharmony_ci goto out_free; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci qid = pref_zq->queue->qid; 11188c2ecf20Sopenharmony_ci rc = pref_zq->ops->send_ep11_cprb(userspace, pref_zq, xcrb, &ap_msg); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 11218c2ecf20Sopenharmony_ci zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); 11228c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ciout_free: 11258c2ecf20Sopenharmony_ci kfree(targets); 11268c2ecf20Sopenharmony_ciout: 11278c2ecf20Sopenharmony_ci ap_release_message(&ap_msg); 11288c2ecf20Sopenharmony_ci if (tr) { 11298c2ecf20Sopenharmony_ci tr->last_rc = rc; 11308c2ecf20Sopenharmony_ci tr->last_qid = qid; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci trace_s390_zcrypt_rep(xcrb, func_code, rc, 11338c2ecf20Sopenharmony_ci AP_QID_CARD(qid), AP_QID_QUEUE(qid)); 11348c2ecf20Sopenharmony_ci return rc; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cilong zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci return _zcrypt_send_ep11_cprb(false, &ap_perms, NULL, xcrb); 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_send_ep11_cprb); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic long zcrypt_rng(char *buffer) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct zcrypt_card *zc, *pref_zc; 11468c2ecf20Sopenharmony_ci struct zcrypt_queue *zq, *pref_zq; 11478c2ecf20Sopenharmony_ci unsigned int wgt = 0, pref_wgt = 0; 11488c2ecf20Sopenharmony_ci unsigned int func_code; 11498c2ecf20Sopenharmony_ci struct ap_message ap_msg; 11508c2ecf20Sopenharmony_ci unsigned int domain; 11518c2ecf20Sopenharmony_ci int qid = 0, rc = -ENODEV; 11528c2ecf20Sopenharmony_ci struct module *mod; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci ap_init_message(&ap_msg); 11578c2ecf20Sopenharmony_ci rc = get_rng_fc(&ap_msg, &func_code, &domain); 11588c2ecf20Sopenharmony_ci if (rc) 11598c2ecf20Sopenharmony_ci goto out; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci pref_zc = NULL; 11628c2ecf20Sopenharmony_ci pref_zq = NULL; 11638c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 11648c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 11658c2ecf20Sopenharmony_ci /* Check for useable CCA card */ 11668c2ecf20Sopenharmony_ci if (!zc->online || !zc->card->config || 11678c2ecf20Sopenharmony_ci !(zc->card->functions & 0x10000000)) 11688c2ecf20Sopenharmony_ci continue; 11698c2ecf20Sopenharmony_ci /* get weight index of the card device */ 11708c2ecf20Sopenharmony_ci wgt = zc->speed_rating[func_code]; 11718c2ecf20Sopenharmony_ci if (!zcrypt_card_compare(zc, pref_zc, wgt, pref_wgt)) 11728c2ecf20Sopenharmony_ci continue; 11738c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 11748c2ecf20Sopenharmony_ci /* check if device is useable and eligible */ 11758c2ecf20Sopenharmony_ci if (!zq->online || !zq->ops->rng || 11768c2ecf20Sopenharmony_ci !zq->queue->config) 11778c2ecf20Sopenharmony_ci continue; 11788c2ecf20Sopenharmony_ci if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt)) 11798c2ecf20Sopenharmony_ci continue; 11808c2ecf20Sopenharmony_ci pref_zc = zc; 11818c2ecf20Sopenharmony_ci pref_zq = zq; 11828c2ecf20Sopenharmony_ci pref_wgt = wgt; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); 11868c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (!pref_zq) { 11898c2ecf20Sopenharmony_ci rc = -ENODEV; 11908c2ecf20Sopenharmony_ci goto out; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci qid = pref_zq->queue->qid; 11948c2ecf20Sopenharmony_ci rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 11978c2ecf20Sopenharmony_ci zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); 11988c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ciout: 12018c2ecf20Sopenharmony_ci ap_release_message(&ap_msg); 12028c2ecf20Sopenharmony_ci trace_s390_zcrypt_rep(buffer, func_code, rc, 12038c2ecf20Sopenharmony_ci AP_QID_CARD(qid), AP_QID_QUEUE(qid)); 12048c2ecf20Sopenharmony_ci return rc; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic void zcrypt_device_status_mask(struct zcrypt_device_status *devstatus) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 12108c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 12118c2ecf20Sopenharmony_ci struct zcrypt_device_status *stat; 12128c2ecf20Sopenharmony_ci int card, queue; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci memset(devstatus, 0, MAX_ZDEV_ENTRIES 12158c2ecf20Sopenharmony_ci * sizeof(struct zcrypt_device_status)); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 12188c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 12198c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 12208c2ecf20Sopenharmony_ci card = AP_QID_CARD(zq->queue->qid); 12218c2ecf20Sopenharmony_ci if (card >= MAX_ZDEV_CARDIDS) 12228c2ecf20Sopenharmony_ci continue; 12238c2ecf20Sopenharmony_ci queue = AP_QID_QUEUE(zq->queue->qid); 12248c2ecf20Sopenharmony_ci stat = &devstatus[card * AP_DOMAINS + queue]; 12258c2ecf20Sopenharmony_ci stat->hwtype = zc->card->ap_dev.device_type; 12268c2ecf20Sopenharmony_ci stat->functions = zc->card->functions >> 26; 12278c2ecf20Sopenharmony_ci stat->qid = zq->queue->qid; 12288c2ecf20Sopenharmony_ci stat->online = zq->online ? 0x01 : 0x00; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_civoid zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 12378c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 12388c2ecf20Sopenharmony_ci struct zcrypt_device_status_ext *stat; 12398c2ecf20Sopenharmony_ci int card, queue; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci memset(devstatus, 0, MAX_ZDEV_ENTRIES_EXT 12428c2ecf20Sopenharmony_ci * sizeof(struct zcrypt_device_status_ext)); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 12458c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 12468c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 12478c2ecf20Sopenharmony_ci card = AP_QID_CARD(zq->queue->qid); 12488c2ecf20Sopenharmony_ci queue = AP_QID_QUEUE(zq->queue->qid); 12498c2ecf20Sopenharmony_ci stat = &devstatus[card * AP_DOMAINS + queue]; 12508c2ecf20Sopenharmony_ci stat->hwtype = zc->card->ap_dev.device_type; 12518c2ecf20Sopenharmony_ci stat->functions = zc->card->functions >> 26; 12528c2ecf20Sopenharmony_ci stat->qid = zq->queue->qid; 12538c2ecf20Sopenharmony_ci stat->online = zq->online ? 0x01 : 0x00; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_device_status_mask_ext); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ciint zcrypt_device_status_ext(int card, int queue, 12618c2ecf20Sopenharmony_ci struct zcrypt_device_status_ext *devstat) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 12648c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci memset(devstat, 0, sizeof(*devstat)); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 12698c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 12708c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 12718c2ecf20Sopenharmony_ci if (card == AP_QID_CARD(zq->queue->qid) && 12728c2ecf20Sopenharmony_ci queue == AP_QID_QUEUE(zq->queue->qid)) { 12738c2ecf20Sopenharmony_ci devstat->hwtype = zc->card->ap_dev.device_type; 12748c2ecf20Sopenharmony_ci devstat->functions = zc->card->functions >> 26; 12758c2ecf20Sopenharmony_ci devstat->qid = zq->queue->qid; 12768c2ecf20Sopenharmony_ci devstat->online = zq->online ? 0x01 : 0x00; 12778c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 12788c2ecf20Sopenharmony_ci return 0; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return -ENODEV; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zcrypt_device_status_ext); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic void zcrypt_status_mask(char status[], size_t max_adapters) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 12918c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 12928c2ecf20Sopenharmony_ci int card; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci memset(status, 0, max_adapters); 12958c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 12968c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 12978c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 12988c2ecf20Sopenharmony_ci card = AP_QID_CARD(zq->queue->qid); 12998c2ecf20Sopenharmony_ci if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index 13008c2ecf20Sopenharmony_ci || card >= max_adapters) 13018c2ecf20Sopenharmony_ci continue; 13028c2ecf20Sopenharmony_ci status[card] = zc->online ? zc->user_space_type : 0x0d; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_cistatic void zcrypt_qdepth_mask(char qdepth[], size_t max_adapters) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 13118c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 13128c2ecf20Sopenharmony_ci int card; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci memset(qdepth, 0, max_adapters); 13158c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 13168c2ecf20Sopenharmony_ci local_bh_disable(); 13178c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 13188c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 13198c2ecf20Sopenharmony_ci card = AP_QID_CARD(zq->queue->qid); 13208c2ecf20Sopenharmony_ci if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index 13218c2ecf20Sopenharmony_ci || card >= max_adapters) 13228c2ecf20Sopenharmony_ci continue; 13238c2ecf20Sopenharmony_ci spin_lock(&zq->queue->lock); 13248c2ecf20Sopenharmony_ci qdepth[card] = 13258c2ecf20Sopenharmony_ci zq->queue->pendingq_count + 13268c2ecf20Sopenharmony_ci zq->queue->requestq_count; 13278c2ecf20Sopenharmony_ci spin_unlock(&zq->queue->lock); 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci local_bh_enable(); 13318c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic void zcrypt_perdev_reqcnt(u32 reqcnt[], size_t max_adapters) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 13378c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 13388c2ecf20Sopenharmony_ci int card; 13398c2ecf20Sopenharmony_ci u64 cnt; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci memset(reqcnt, 0, sizeof(int) * max_adapters); 13428c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 13438c2ecf20Sopenharmony_ci local_bh_disable(); 13448c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 13458c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 13468c2ecf20Sopenharmony_ci card = AP_QID_CARD(zq->queue->qid); 13478c2ecf20Sopenharmony_ci if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index 13488c2ecf20Sopenharmony_ci || card >= max_adapters) 13498c2ecf20Sopenharmony_ci continue; 13508c2ecf20Sopenharmony_ci spin_lock(&zq->queue->lock); 13518c2ecf20Sopenharmony_ci cnt = zq->queue->total_request_count; 13528c2ecf20Sopenharmony_ci spin_unlock(&zq->queue->lock); 13538c2ecf20Sopenharmony_ci reqcnt[card] = (cnt < UINT_MAX) ? (u32) cnt : UINT_MAX; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci local_bh_enable(); 13578c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic int zcrypt_pendingq_count(void) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 13638c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 13648c2ecf20Sopenharmony_ci int pendingq_count; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci pendingq_count = 0; 13678c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 13688c2ecf20Sopenharmony_ci local_bh_disable(); 13698c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 13708c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 13718c2ecf20Sopenharmony_ci if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) 13728c2ecf20Sopenharmony_ci continue; 13738c2ecf20Sopenharmony_ci spin_lock(&zq->queue->lock); 13748c2ecf20Sopenharmony_ci pendingq_count += zq->queue->pendingq_count; 13758c2ecf20Sopenharmony_ci spin_unlock(&zq->queue->lock); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci local_bh_enable(); 13798c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 13808c2ecf20Sopenharmony_ci return pendingq_count; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic int zcrypt_requestq_count(void) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct zcrypt_card *zc; 13868c2ecf20Sopenharmony_ci struct zcrypt_queue *zq; 13878c2ecf20Sopenharmony_ci int requestq_count; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci requestq_count = 0; 13908c2ecf20Sopenharmony_ci spin_lock(&zcrypt_list_lock); 13918c2ecf20Sopenharmony_ci local_bh_disable(); 13928c2ecf20Sopenharmony_ci for_each_zcrypt_card(zc) { 13938c2ecf20Sopenharmony_ci for_each_zcrypt_queue(zq, zc) { 13948c2ecf20Sopenharmony_ci if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) 13958c2ecf20Sopenharmony_ci continue; 13968c2ecf20Sopenharmony_ci spin_lock(&zq->queue->lock); 13978c2ecf20Sopenharmony_ci requestq_count += zq->queue->requestq_count; 13988c2ecf20Sopenharmony_ci spin_unlock(&zq->queue->lock); 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci local_bh_enable(); 14028c2ecf20Sopenharmony_ci spin_unlock(&zcrypt_list_lock); 14038c2ecf20Sopenharmony_ci return requestq_count; 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_cistatic int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci int rc; 14098c2ecf20Sopenharmony_ci struct zcrypt_track tr; 14108c2ecf20Sopenharmony_ci struct ica_rsa_modexpo mex; 14118c2ecf20Sopenharmony_ci struct ica_rsa_modexpo __user *umex = (void __user *) arg; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 14148c2ecf20Sopenharmony_ci if (copy_from_user(&mex, umex, sizeof(mex))) 14158c2ecf20Sopenharmony_ci return -EFAULT; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 14188c2ecf20Sopenharmony_ci if (mex.inputdatalength & (1U << 31)) { 14198c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 14208c2ecf20Sopenharmony_ci return -EPERM; 14218c2ecf20Sopenharmony_ci tr.fi.cmd = (u16)(mex.inputdatalength >> 16); 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci mex.inputdatalength &= 0x0000FFFF; 14248c2ecf20Sopenharmony_ci#endif 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci do { 14278c2ecf20Sopenharmony_ci rc = zcrypt_rsa_modexpo(perms, &tr, &mex); 14288c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 14298c2ecf20Sopenharmony_ci tr.again_counter++; 14308c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 14318c2ecf20Sopenharmony_ci if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci#endif 14348c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 14358c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 14368c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 14378c2ecf20Sopenharmony_ci do { 14388c2ecf20Sopenharmony_ci rc = zcrypt_rsa_modexpo(perms, &tr, &mex); 14398c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 14408c2ecf20Sopenharmony_ci tr.again_counter++; 14418c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 14428c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 14438c2ecf20Sopenharmony_ci rc = -EIO; 14448c2ecf20Sopenharmony_ci if (rc) { 14458c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc); 14468c2ecf20Sopenharmony_ci return rc; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci return put_user(mex.outputdatalength, &umex->outputdatalength); 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cistatic int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci int rc; 14548c2ecf20Sopenharmony_ci struct zcrypt_track tr; 14558c2ecf20Sopenharmony_ci struct ica_rsa_modexpo_crt crt; 14568c2ecf20Sopenharmony_ci struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 14598c2ecf20Sopenharmony_ci if (copy_from_user(&crt, ucrt, sizeof(crt))) 14608c2ecf20Sopenharmony_ci return -EFAULT; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 14638c2ecf20Sopenharmony_ci if (crt.inputdatalength & (1U << 31)) { 14648c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 14658c2ecf20Sopenharmony_ci return -EPERM; 14668c2ecf20Sopenharmony_ci tr.fi.cmd = (u16)(crt.inputdatalength >> 16); 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci crt.inputdatalength &= 0x0000FFFF; 14698c2ecf20Sopenharmony_ci#endif 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci do { 14728c2ecf20Sopenharmony_ci rc = zcrypt_rsa_crt(perms, &tr, &crt); 14738c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 14748c2ecf20Sopenharmony_ci tr.again_counter++; 14758c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 14768c2ecf20Sopenharmony_ci if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) 14778c2ecf20Sopenharmony_ci break; 14788c2ecf20Sopenharmony_ci#endif 14798c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 14808c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 14818c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 14828c2ecf20Sopenharmony_ci do { 14838c2ecf20Sopenharmony_ci rc = zcrypt_rsa_crt(perms, &tr, &crt); 14848c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 14858c2ecf20Sopenharmony_ci tr.again_counter++; 14868c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 14878c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 14888c2ecf20Sopenharmony_ci rc = -EIO; 14898c2ecf20Sopenharmony_ci if (rc) { 14908c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc); 14918c2ecf20Sopenharmony_ci return rc; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci return put_user(crt.outputdatalength, &ucrt->outputdatalength); 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg) 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci int rc; 14998c2ecf20Sopenharmony_ci struct ica_xcRB xcRB; 15008c2ecf20Sopenharmony_ci struct zcrypt_track tr; 15018c2ecf20Sopenharmony_ci struct ica_xcRB __user *uxcRB = (void __user *) arg; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 15048c2ecf20Sopenharmony_ci if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) 15058c2ecf20Sopenharmony_ci return -EFAULT; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 15088c2ecf20Sopenharmony_ci if (xcRB.status & (1U << 31)) { 15098c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 15108c2ecf20Sopenharmony_ci return -EPERM; 15118c2ecf20Sopenharmony_ci tr.fi.cmd = (u16)(xcRB.status >> 16); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci xcRB.status &= 0x0000FFFF; 15148c2ecf20Sopenharmony_ci#endif 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci do { 15178c2ecf20Sopenharmony_ci rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB); 15188c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 15198c2ecf20Sopenharmony_ci tr.again_counter++; 15208c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 15218c2ecf20Sopenharmony_ci if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) 15228c2ecf20Sopenharmony_ci break; 15238c2ecf20Sopenharmony_ci#endif 15248c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 15258c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 15268c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 15278c2ecf20Sopenharmony_ci do { 15288c2ecf20Sopenharmony_ci rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB); 15298c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 15308c2ecf20Sopenharmony_ci tr.again_counter++; 15318c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 15328c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 15338c2ecf20Sopenharmony_ci rc = -EIO; 15348c2ecf20Sopenharmony_ci if (rc) 15358c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n", 15368c2ecf20Sopenharmony_ci rc, xcRB.status); 15378c2ecf20Sopenharmony_ci if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) 15388c2ecf20Sopenharmony_ci return -EFAULT; 15398c2ecf20Sopenharmony_ci return rc; 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_cistatic int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci int rc; 15458c2ecf20Sopenharmony_ci struct ep11_urb xcrb; 15468c2ecf20Sopenharmony_ci struct zcrypt_track tr; 15478c2ecf20Sopenharmony_ci struct ep11_urb __user *uxcrb = (void __user *)arg; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 15508c2ecf20Sopenharmony_ci if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) 15518c2ecf20Sopenharmony_ci return -EFAULT; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 15548c2ecf20Sopenharmony_ci if (xcrb.req_len & (1ULL << 63)) { 15558c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 15568c2ecf20Sopenharmony_ci return -EPERM; 15578c2ecf20Sopenharmony_ci tr.fi.cmd = (u16)(xcrb.req_len >> 48); 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci xcrb.req_len &= 0x0000FFFFFFFFFFFFULL; 15608c2ecf20Sopenharmony_ci#endif 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci do { 15638c2ecf20Sopenharmony_ci rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb); 15648c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 15658c2ecf20Sopenharmony_ci tr.again_counter++; 15668c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 15678c2ecf20Sopenharmony_ci if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) 15688c2ecf20Sopenharmony_ci break; 15698c2ecf20Sopenharmony_ci#endif 15708c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 15718c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 15728c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 15738c2ecf20Sopenharmony_ci do { 15748c2ecf20Sopenharmony_ci rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb); 15758c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 15768c2ecf20Sopenharmony_ci tr.again_counter++; 15778c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 15788c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 15798c2ecf20Sopenharmony_ci rc = -EIO; 15808c2ecf20Sopenharmony_ci if (rc) 15818c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc); 15828c2ecf20Sopenharmony_ci if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb))) 15838c2ecf20Sopenharmony_ci return -EFAULT; 15848c2ecf20Sopenharmony_ci return rc; 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, 15888c2ecf20Sopenharmony_ci unsigned long arg) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci int rc; 15918c2ecf20Sopenharmony_ci struct ap_perms *perms = 15928c2ecf20Sopenharmony_ci (struct ap_perms *) filp->private_data; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci rc = zcrypt_check_ioctl(perms, cmd); 15958c2ecf20Sopenharmony_ci if (rc) 15968c2ecf20Sopenharmony_ci return rc; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci switch (cmd) { 15998c2ecf20Sopenharmony_ci case ICARSAMODEXPO: 16008c2ecf20Sopenharmony_ci return icarsamodexpo_ioctl(perms, arg); 16018c2ecf20Sopenharmony_ci case ICARSACRT: 16028c2ecf20Sopenharmony_ci return icarsacrt_ioctl(perms, arg); 16038c2ecf20Sopenharmony_ci case ZSECSENDCPRB: 16048c2ecf20Sopenharmony_ci return zsecsendcprb_ioctl(perms, arg); 16058c2ecf20Sopenharmony_ci case ZSENDEP11CPRB: 16068c2ecf20Sopenharmony_ci return zsendep11cprb_ioctl(perms, arg); 16078c2ecf20Sopenharmony_ci case ZCRYPT_DEVICE_STATUS: { 16088c2ecf20Sopenharmony_ci struct zcrypt_device_status_ext *device_status; 16098c2ecf20Sopenharmony_ci size_t total_size = MAX_ZDEV_ENTRIES_EXT 16108c2ecf20Sopenharmony_ci * sizeof(struct zcrypt_device_status_ext); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci device_status = kzalloc(total_size, GFP_KERNEL); 16138c2ecf20Sopenharmony_ci if (!device_status) 16148c2ecf20Sopenharmony_ci return -ENOMEM; 16158c2ecf20Sopenharmony_ci zcrypt_device_status_mask_ext(device_status); 16168c2ecf20Sopenharmony_ci if (copy_to_user((char __user *) arg, device_status, 16178c2ecf20Sopenharmony_ci total_size)) 16188c2ecf20Sopenharmony_ci rc = -EFAULT; 16198c2ecf20Sopenharmony_ci kfree(device_status); 16208c2ecf20Sopenharmony_ci return rc; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci case ZCRYPT_STATUS_MASK: { 16238c2ecf20Sopenharmony_ci char status[AP_DEVICES]; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci zcrypt_status_mask(status, AP_DEVICES); 16268c2ecf20Sopenharmony_ci if (copy_to_user((char __user *) arg, status, sizeof(status))) 16278c2ecf20Sopenharmony_ci return -EFAULT; 16288c2ecf20Sopenharmony_ci return 0; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci case ZCRYPT_QDEPTH_MASK: { 16318c2ecf20Sopenharmony_ci char qdepth[AP_DEVICES]; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci zcrypt_qdepth_mask(qdepth, AP_DEVICES); 16348c2ecf20Sopenharmony_ci if (copy_to_user((char __user *) arg, qdepth, sizeof(qdepth))) 16358c2ecf20Sopenharmony_ci return -EFAULT; 16368c2ecf20Sopenharmony_ci return 0; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci case ZCRYPT_PERDEV_REQCNT: { 16398c2ecf20Sopenharmony_ci u32 *reqcnt; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci reqcnt = kcalloc(AP_DEVICES, sizeof(u32), GFP_KERNEL); 16428c2ecf20Sopenharmony_ci if (!reqcnt) 16438c2ecf20Sopenharmony_ci return -ENOMEM; 16448c2ecf20Sopenharmony_ci zcrypt_perdev_reqcnt(reqcnt, AP_DEVICES); 16458c2ecf20Sopenharmony_ci if (copy_to_user((int __user *) arg, reqcnt, 16468c2ecf20Sopenharmony_ci sizeof(u32) * AP_DEVICES)) 16478c2ecf20Sopenharmony_ci rc = -EFAULT; 16488c2ecf20Sopenharmony_ci kfree(reqcnt); 16498c2ecf20Sopenharmony_ci return rc; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci case Z90STAT_REQUESTQ_COUNT: 16528c2ecf20Sopenharmony_ci return put_user(zcrypt_requestq_count(), (int __user *) arg); 16538c2ecf20Sopenharmony_ci case Z90STAT_PENDINGQ_COUNT: 16548c2ecf20Sopenharmony_ci return put_user(zcrypt_pendingq_count(), (int __user *) arg); 16558c2ecf20Sopenharmony_ci case Z90STAT_TOTALOPEN_COUNT: 16568c2ecf20Sopenharmony_ci return put_user(atomic_read(&zcrypt_open_count), 16578c2ecf20Sopenharmony_ci (int __user *) arg); 16588c2ecf20Sopenharmony_ci case Z90STAT_DOMAIN_INDEX: 16598c2ecf20Sopenharmony_ci return put_user(ap_domain_index, (int __user *) arg); 16608c2ecf20Sopenharmony_ci /* 16618c2ecf20Sopenharmony_ci * Deprecated ioctls 16628c2ecf20Sopenharmony_ci */ 16638c2ecf20Sopenharmony_ci case ZDEVICESTATUS: { 16648c2ecf20Sopenharmony_ci /* the old ioctl supports only 64 adapters */ 16658c2ecf20Sopenharmony_ci struct zcrypt_device_status *device_status; 16668c2ecf20Sopenharmony_ci size_t total_size = MAX_ZDEV_ENTRIES 16678c2ecf20Sopenharmony_ci * sizeof(struct zcrypt_device_status); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci device_status = kzalloc(total_size, GFP_KERNEL); 16708c2ecf20Sopenharmony_ci if (!device_status) 16718c2ecf20Sopenharmony_ci return -ENOMEM; 16728c2ecf20Sopenharmony_ci zcrypt_device_status_mask(device_status); 16738c2ecf20Sopenharmony_ci if (copy_to_user((char __user *) arg, device_status, 16748c2ecf20Sopenharmony_ci total_size)) 16758c2ecf20Sopenharmony_ci rc = -EFAULT; 16768c2ecf20Sopenharmony_ci kfree(device_status); 16778c2ecf20Sopenharmony_ci return rc; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci case Z90STAT_STATUS_MASK: { 16808c2ecf20Sopenharmony_ci /* the old ioctl supports only 64 adapters */ 16818c2ecf20Sopenharmony_ci char status[MAX_ZDEV_CARDIDS]; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci zcrypt_status_mask(status, MAX_ZDEV_CARDIDS); 16848c2ecf20Sopenharmony_ci if (copy_to_user((char __user *) arg, status, sizeof(status))) 16858c2ecf20Sopenharmony_ci return -EFAULT; 16868c2ecf20Sopenharmony_ci return 0; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci case Z90STAT_QDEPTH_MASK: { 16898c2ecf20Sopenharmony_ci /* the old ioctl supports only 64 adapters */ 16908c2ecf20Sopenharmony_ci char qdepth[MAX_ZDEV_CARDIDS]; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci zcrypt_qdepth_mask(qdepth, MAX_ZDEV_CARDIDS); 16938c2ecf20Sopenharmony_ci if (copy_to_user((char __user *) arg, qdepth, sizeof(qdepth))) 16948c2ecf20Sopenharmony_ci return -EFAULT; 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci case Z90STAT_PERDEV_REQCNT: { 16988c2ecf20Sopenharmony_ci /* the old ioctl supports only 64 adapters */ 16998c2ecf20Sopenharmony_ci u32 reqcnt[MAX_ZDEV_CARDIDS]; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci zcrypt_perdev_reqcnt(reqcnt, MAX_ZDEV_CARDIDS); 17028c2ecf20Sopenharmony_ci if (copy_to_user((int __user *) arg, reqcnt, sizeof(reqcnt))) 17038c2ecf20Sopenharmony_ci return -EFAULT; 17048c2ecf20Sopenharmony_ci return 0; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci /* unknown ioctl number */ 17078c2ecf20Sopenharmony_ci default: 17088c2ecf20Sopenharmony_ci ZCRYPT_DBF(DBF_DEBUG, "unknown ioctl 0x%08x\n", cmd); 17098c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17148c2ecf20Sopenharmony_ci/* 17158c2ecf20Sopenharmony_ci * ioctl32 conversion routines 17168c2ecf20Sopenharmony_ci */ 17178c2ecf20Sopenharmony_cistruct compat_ica_rsa_modexpo { 17188c2ecf20Sopenharmony_ci compat_uptr_t inputdata; 17198c2ecf20Sopenharmony_ci unsigned int inputdatalength; 17208c2ecf20Sopenharmony_ci compat_uptr_t outputdata; 17218c2ecf20Sopenharmony_ci unsigned int outputdatalength; 17228c2ecf20Sopenharmony_ci compat_uptr_t b_key; 17238c2ecf20Sopenharmony_ci compat_uptr_t n_modulus; 17248c2ecf20Sopenharmony_ci}; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistatic long trans_modexpo32(struct ap_perms *perms, struct file *filp, 17278c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg); 17308c2ecf20Sopenharmony_ci struct compat_ica_rsa_modexpo mex32; 17318c2ecf20Sopenharmony_ci struct ica_rsa_modexpo mex64; 17328c2ecf20Sopenharmony_ci struct zcrypt_track tr; 17338c2ecf20Sopenharmony_ci long rc; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 17368c2ecf20Sopenharmony_ci if (copy_from_user(&mex32, umex32, sizeof(mex32))) 17378c2ecf20Sopenharmony_ci return -EFAULT; 17388c2ecf20Sopenharmony_ci mex64.inputdata = compat_ptr(mex32.inputdata); 17398c2ecf20Sopenharmony_ci mex64.inputdatalength = mex32.inputdatalength; 17408c2ecf20Sopenharmony_ci mex64.outputdata = compat_ptr(mex32.outputdata); 17418c2ecf20Sopenharmony_ci mex64.outputdatalength = mex32.outputdatalength; 17428c2ecf20Sopenharmony_ci mex64.b_key = compat_ptr(mex32.b_key); 17438c2ecf20Sopenharmony_ci mex64.n_modulus = compat_ptr(mex32.n_modulus); 17448c2ecf20Sopenharmony_ci do { 17458c2ecf20Sopenharmony_ci rc = zcrypt_rsa_modexpo(perms, &tr, &mex64); 17468c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 17478c2ecf20Sopenharmony_ci tr.again_counter++; 17488c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 17498c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 17508c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 17518c2ecf20Sopenharmony_ci do { 17528c2ecf20Sopenharmony_ci rc = zcrypt_rsa_modexpo(perms, &tr, &mex64); 17538c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 17548c2ecf20Sopenharmony_ci tr.again_counter++; 17558c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 17568c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 17578c2ecf20Sopenharmony_ci rc = -EIO; 17588c2ecf20Sopenharmony_ci if (rc) 17598c2ecf20Sopenharmony_ci return rc; 17608c2ecf20Sopenharmony_ci return put_user(mex64.outputdatalength, 17618c2ecf20Sopenharmony_ci &umex32->outputdatalength); 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistruct compat_ica_rsa_modexpo_crt { 17658c2ecf20Sopenharmony_ci compat_uptr_t inputdata; 17668c2ecf20Sopenharmony_ci unsigned int inputdatalength; 17678c2ecf20Sopenharmony_ci compat_uptr_t outputdata; 17688c2ecf20Sopenharmony_ci unsigned int outputdatalength; 17698c2ecf20Sopenharmony_ci compat_uptr_t bp_key; 17708c2ecf20Sopenharmony_ci compat_uptr_t bq_key; 17718c2ecf20Sopenharmony_ci compat_uptr_t np_prime; 17728c2ecf20Sopenharmony_ci compat_uptr_t nq_prime; 17738c2ecf20Sopenharmony_ci compat_uptr_t u_mult_inv; 17748c2ecf20Sopenharmony_ci}; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_cistatic long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp, 17778c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg); 17808c2ecf20Sopenharmony_ci struct compat_ica_rsa_modexpo_crt crt32; 17818c2ecf20Sopenharmony_ci struct ica_rsa_modexpo_crt crt64; 17828c2ecf20Sopenharmony_ci struct zcrypt_track tr; 17838c2ecf20Sopenharmony_ci long rc; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 17868c2ecf20Sopenharmony_ci if (copy_from_user(&crt32, ucrt32, sizeof(crt32))) 17878c2ecf20Sopenharmony_ci return -EFAULT; 17888c2ecf20Sopenharmony_ci crt64.inputdata = compat_ptr(crt32.inputdata); 17898c2ecf20Sopenharmony_ci crt64.inputdatalength = crt32.inputdatalength; 17908c2ecf20Sopenharmony_ci crt64.outputdata = compat_ptr(crt32.outputdata); 17918c2ecf20Sopenharmony_ci crt64.outputdatalength = crt32.outputdatalength; 17928c2ecf20Sopenharmony_ci crt64.bp_key = compat_ptr(crt32.bp_key); 17938c2ecf20Sopenharmony_ci crt64.bq_key = compat_ptr(crt32.bq_key); 17948c2ecf20Sopenharmony_ci crt64.np_prime = compat_ptr(crt32.np_prime); 17958c2ecf20Sopenharmony_ci crt64.nq_prime = compat_ptr(crt32.nq_prime); 17968c2ecf20Sopenharmony_ci crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv); 17978c2ecf20Sopenharmony_ci do { 17988c2ecf20Sopenharmony_ci rc = zcrypt_rsa_crt(perms, &tr, &crt64); 17998c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 18008c2ecf20Sopenharmony_ci tr.again_counter++; 18018c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 18028c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 18038c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 18048c2ecf20Sopenharmony_ci do { 18058c2ecf20Sopenharmony_ci rc = zcrypt_rsa_crt(perms, &tr, &crt64); 18068c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 18078c2ecf20Sopenharmony_ci tr.again_counter++; 18088c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 18098c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 18108c2ecf20Sopenharmony_ci rc = -EIO; 18118c2ecf20Sopenharmony_ci if (rc) 18128c2ecf20Sopenharmony_ci return rc; 18138c2ecf20Sopenharmony_ci return put_user(crt64.outputdatalength, 18148c2ecf20Sopenharmony_ci &ucrt32->outputdatalength); 18158c2ecf20Sopenharmony_ci} 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_cistruct compat_ica_xcRB { 18188c2ecf20Sopenharmony_ci unsigned short agent_ID; 18198c2ecf20Sopenharmony_ci unsigned int user_defined; 18208c2ecf20Sopenharmony_ci unsigned short request_ID; 18218c2ecf20Sopenharmony_ci unsigned int request_control_blk_length; 18228c2ecf20Sopenharmony_ci unsigned char padding1[16 - sizeof(compat_uptr_t)]; 18238c2ecf20Sopenharmony_ci compat_uptr_t request_control_blk_addr; 18248c2ecf20Sopenharmony_ci unsigned int request_data_length; 18258c2ecf20Sopenharmony_ci char padding2[16 - sizeof(compat_uptr_t)]; 18268c2ecf20Sopenharmony_ci compat_uptr_t request_data_address; 18278c2ecf20Sopenharmony_ci unsigned int reply_control_blk_length; 18288c2ecf20Sopenharmony_ci char padding3[16 - sizeof(compat_uptr_t)]; 18298c2ecf20Sopenharmony_ci compat_uptr_t reply_control_blk_addr; 18308c2ecf20Sopenharmony_ci unsigned int reply_data_length; 18318c2ecf20Sopenharmony_ci char padding4[16 - sizeof(compat_uptr_t)]; 18328c2ecf20Sopenharmony_ci compat_uptr_t reply_data_addr; 18338c2ecf20Sopenharmony_ci unsigned short priority_window; 18348c2ecf20Sopenharmony_ci unsigned int status; 18358c2ecf20Sopenharmony_ci} __packed; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_cistatic long trans_xcRB32(struct ap_perms *perms, struct file *filp, 18388c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 18398c2ecf20Sopenharmony_ci{ 18408c2ecf20Sopenharmony_ci struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg); 18418c2ecf20Sopenharmony_ci struct compat_ica_xcRB xcRB32; 18428c2ecf20Sopenharmony_ci struct zcrypt_track tr; 18438c2ecf20Sopenharmony_ci struct ica_xcRB xcRB64; 18448c2ecf20Sopenharmony_ci long rc; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci memset(&tr, 0, sizeof(tr)); 18478c2ecf20Sopenharmony_ci if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32))) 18488c2ecf20Sopenharmony_ci return -EFAULT; 18498c2ecf20Sopenharmony_ci xcRB64.agent_ID = xcRB32.agent_ID; 18508c2ecf20Sopenharmony_ci xcRB64.user_defined = xcRB32.user_defined; 18518c2ecf20Sopenharmony_ci xcRB64.request_ID = xcRB32.request_ID; 18528c2ecf20Sopenharmony_ci xcRB64.request_control_blk_length = 18538c2ecf20Sopenharmony_ci xcRB32.request_control_blk_length; 18548c2ecf20Sopenharmony_ci xcRB64.request_control_blk_addr = 18558c2ecf20Sopenharmony_ci compat_ptr(xcRB32.request_control_blk_addr); 18568c2ecf20Sopenharmony_ci xcRB64.request_data_length = 18578c2ecf20Sopenharmony_ci xcRB32.request_data_length; 18588c2ecf20Sopenharmony_ci xcRB64.request_data_address = 18598c2ecf20Sopenharmony_ci compat_ptr(xcRB32.request_data_address); 18608c2ecf20Sopenharmony_ci xcRB64.reply_control_blk_length = 18618c2ecf20Sopenharmony_ci xcRB32.reply_control_blk_length; 18628c2ecf20Sopenharmony_ci xcRB64.reply_control_blk_addr = 18638c2ecf20Sopenharmony_ci compat_ptr(xcRB32.reply_control_blk_addr); 18648c2ecf20Sopenharmony_ci xcRB64.reply_data_length = xcRB32.reply_data_length; 18658c2ecf20Sopenharmony_ci xcRB64.reply_data_addr = 18668c2ecf20Sopenharmony_ci compat_ptr(xcRB32.reply_data_addr); 18678c2ecf20Sopenharmony_ci xcRB64.priority_window = xcRB32.priority_window; 18688c2ecf20Sopenharmony_ci xcRB64.status = xcRB32.status; 18698c2ecf20Sopenharmony_ci do { 18708c2ecf20Sopenharmony_ci rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB64); 18718c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 18728c2ecf20Sopenharmony_ci tr.again_counter++; 18738c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 18748c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 18758c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 18768c2ecf20Sopenharmony_ci do { 18778c2ecf20Sopenharmony_ci rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB64); 18788c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 18798c2ecf20Sopenharmony_ci tr.again_counter++; 18808c2ecf20Sopenharmony_ci } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); 18818c2ecf20Sopenharmony_ci if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX) 18828c2ecf20Sopenharmony_ci rc = -EIO; 18838c2ecf20Sopenharmony_ci xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; 18848c2ecf20Sopenharmony_ci xcRB32.reply_data_length = xcRB64.reply_data_length; 18858c2ecf20Sopenharmony_ci xcRB32.status = xcRB64.status; 18868c2ecf20Sopenharmony_ci if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32))) 18878c2ecf20Sopenharmony_ci return -EFAULT; 18888c2ecf20Sopenharmony_ci return rc; 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistatic long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, 18928c2ecf20Sopenharmony_ci unsigned long arg) 18938c2ecf20Sopenharmony_ci{ 18948c2ecf20Sopenharmony_ci int rc; 18958c2ecf20Sopenharmony_ci struct ap_perms *perms = 18968c2ecf20Sopenharmony_ci (struct ap_perms *) filp->private_data; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci rc = zcrypt_check_ioctl(perms, cmd); 18998c2ecf20Sopenharmony_ci if (rc) 19008c2ecf20Sopenharmony_ci return rc; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (cmd == ICARSAMODEXPO) 19038c2ecf20Sopenharmony_ci return trans_modexpo32(perms, filp, cmd, arg); 19048c2ecf20Sopenharmony_ci if (cmd == ICARSACRT) 19058c2ecf20Sopenharmony_ci return trans_modexpo_crt32(perms, filp, cmd, arg); 19068c2ecf20Sopenharmony_ci if (cmd == ZSECSENDCPRB) 19078c2ecf20Sopenharmony_ci return trans_xcRB32(perms, filp, cmd, arg); 19088c2ecf20Sopenharmony_ci return zcrypt_unlocked_ioctl(filp, cmd, arg); 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci#endif 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci/* 19138c2ecf20Sopenharmony_ci * Misc device file operations. 19148c2ecf20Sopenharmony_ci */ 19158c2ecf20Sopenharmony_cistatic const struct file_operations zcrypt_fops = { 19168c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 19178c2ecf20Sopenharmony_ci .read = zcrypt_read, 19188c2ecf20Sopenharmony_ci .write = zcrypt_write, 19198c2ecf20Sopenharmony_ci .unlocked_ioctl = zcrypt_unlocked_ioctl, 19208c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 19218c2ecf20Sopenharmony_ci .compat_ioctl = zcrypt_compat_ioctl, 19228c2ecf20Sopenharmony_ci#endif 19238c2ecf20Sopenharmony_ci .open = zcrypt_open, 19248c2ecf20Sopenharmony_ci .release = zcrypt_release, 19258c2ecf20Sopenharmony_ci .llseek = no_llseek, 19268c2ecf20Sopenharmony_ci}; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci/* 19298c2ecf20Sopenharmony_ci * Misc device. 19308c2ecf20Sopenharmony_ci */ 19318c2ecf20Sopenharmony_cistatic struct miscdevice zcrypt_misc_device = { 19328c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 19338c2ecf20Sopenharmony_ci .name = "z90crypt", 19348c2ecf20Sopenharmony_ci .fops = &zcrypt_fops, 19358c2ecf20Sopenharmony_ci}; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_cistatic int zcrypt_rng_device_count; 19388c2ecf20Sopenharmony_cistatic u32 *zcrypt_rng_buffer; 19398c2ecf20Sopenharmony_cistatic int zcrypt_rng_buffer_index; 19408c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(zcrypt_rng_mutex); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci int rc; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci /* 19478c2ecf20Sopenharmony_ci * We don't need locking here because the RNG API guarantees serialized 19488c2ecf20Sopenharmony_ci * read method calls. 19498c2ecf20Sopenharmony_ci */ 19508c2ecf20Sopenharmony_ci if (zcrypt_rng_buffer_index == 0) { 19518c2ecf20Sopenharmony_ci rc = zcrypt_rng((char *) zcrypt_rng_buffer); 19528c2ecf20Sopenharmony_ci /* on failure: retry once again after a requested rescan */ 19538c2ecf20Sopenharmony_ci if ((rc == -ENODEV) && (zcrypt_process_rescan())) 19548c2ecf20Sopenharmony_ci rc = zcrypt_rng((char *) zcrypt_rng_buffer); 19558c2ecf20Sopenharmony_ci if (rc < 0) 19568c2ecf20Sopenharmony_ci return -EIO; 19578c2ecf20Sopenharmony_ci zcrypt_rng_buffer_index = rc / sizeof(*data); 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci *data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index]; 19608c2ecf20Sopenharmony_ci return sizeof(*data); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_cistatic struct hwrng zcrypt_rng_dev = { 19648c2ecf20Sopenharmony_ci .name = "zcrypt", 19658c2ecf20Sopenharmony_ci .data_read = zcrypt_rng_data_read, 19668c2ecf20Sopenharmony_ci .quality = 990, 19678c2ecf20Sopenharmony_ci}; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ciint zcrypt_rng_device_add(void) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci int rc = 0; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci mutex_lock(&zcrypt_rng_mutex); 19748c2ecf20Sopenharmony_ci if (zcrypt_rng_device_count == 0) { 19758c2ecf20Sopenharmony_ci zcrypt_rng_buffer = (u32 *) get_zeroed_page(GFP_KERNEL); 19768c2ecf20Sopenharmony_ci if (!zcrypt_rng_buffer) { 19778c2ecf20Sopenharmony_ci rc = -ENOMEM; 19788c2ecf20Sopenharmony_ci goto out; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci zcrypt_rng_buffer_index = 0; 19818c2ecf20Sopenharmony_ci if (!zcrypt_hwrng_seed) 19828c2ecf20Sopenharmony_ci zcrypt_rng_dev.quality = 0; 19838c2ecf20Sopenharmony_ci rc = hwrng_register(&zcrypt_rng_dev); 19848c2ecf20Sopenharmony_ci if (rc) 19858c2ecf20Sopenharmony_ci goto out_free; 19868c2ecf20Sopenharmony_ci zcrypt_rng_device_count = 1; 19878c2ecf20Sopenharmony_ci } else 19888c2ecf20Sopenharmony_ci zcrypt_rng_device_count++; 19898c2ecf20Sopenharmony_ci mutex_unlock(&zcrypt_rng_mutex); 19908c2ecf20Sopenharmony_ci return 0; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ciout_free: 19938c2ecf20Sopenharmony_ci free_page((unsigned long) zcrypt_rng_buffer); 19948c2ecf20Sopenharmony_ciout: 19958c2ecf20Sopenharmony_ci mutex_unlock(&zcrypt_rng_mutex); 19968c2ecf20Sopenharmony_ci return rc; 19978c2ecf20Sopenharmony_ci} 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_civoid zcrypt_rng_device_remove(void) 20008c2ecf20Sopenharmony_ci{ 20018c2ecf20Sopenharmony_ci mutex_lock(&zcrypt_rng_mutex); 20028c2ecf20Sopenharmony_ci zcrypt_rng_device_count--; 20038c2ecf20Sopenharmony_ci if (zcrypt_rng_device_count == 0) { 20048c2ecf20Sopenharmony_ci hwrng_unregister(&zcrypt_rng_dev); 20058c2ecf20Sopenharmony_ci free_page((unsigned long) zcrypt_rng_buffer); 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci mutex_unlock(&zcrypt_rng_mutex); 20088c2ecf20Sopenharmony_ci} 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ciint __init zcrypt_debug_init(void) 20118c2ecf20Sopenharmony_ci{ 20128c2ecf20Sopenharmony_ci zcrypt_dbf_info = debug_register("zcrypt", 1, 1, 20138c2ecf20Sopenharmony_ci DBF_MAX_SPRINTF_ARGS * sizeof(long)); 20148c2ecf20Sopenharmony_ci debug_register_view(zcrypt_dbf_info, &debug_sprintf_view); 20158c2ecf20Sopenharmony_ci debug_set_level(zcrypt_dbf_info, DBF_ERR); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci return 0; 20188c2ecf20Sopenharmony_ci} 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_civoid zcrypt_debug_exit(void) 20218c2ecf20Sopenharmony_ci{ 20228c2ecf20Sopenharmony_ci debug_unregister(zcrypt_dbf_info); 20238c2ecf20Sopenharmony_ci} 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_cistatic int __init zcdn_init(void) 20288c2ecf20Sopenharmony_ci{ 20298c2ecf20Sopenharmony_ci int rc; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci /* create a new class 'zcrypt' */ 20328c2ecf20Sopenharmony_ci zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME); 20338c2ecf20Sopenharmony_ci if (IS_ERR(zcrypt_class)) { 20348c2ecf20Sopenharmony_ci rc = PTR_ERR(zcrypt_class); 20358c2ecf20Sopenharmony_ci goto out_class_create_failed; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci zcrypt_class->dev_release = zcdn_device_release; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci /* alloc device minor range */ 20408c2ecf20Sopenharmony_ci rc = alloc_chrdev_region(&zcrypt_devt, 20418c2ecf20Sopenharmony_ci 0, ZCRYPT_MAX_MINOR_NODES, 20428c2ecf20Sopenharmony_ci ZCRYPT_NAME); 20438c2ecf20Sopenharmony_ci if (rc) 20448c2ecf20Sopenharmony_ci goto out_alloc_chrdev_failed; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci cdev_init(&zcrypt_cdev, &zcrypt_fops); 20478c2ecf20Sopenharmony_ci zcrypt_cdev.owner = THIS_MODULE; 20488c2ecf20Sopenharmony_ci rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES); 20498c2ecf20Sopenharmony_ci if (rc) 20508c2ecf20Sopenharmony_ci goto out_cdev_add_failed; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci /* need some class specific sysfs attributes */ 20538c2ecf20Sopenharmony_ci rc = class_create_file(zcrypt_class, &class_attr_zcdn_create); 20548c2ecf20Sopenharmony_ci if (rc) 20558c2ecf20Sopenharmony_ci goto out_class_create_file_1_failed; 20568c2ecf20Sopenharmony_ci rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy); 20578c2ecf20Sopenharmony_ci if (rc) 20588c2ecf20Sopenharmony_ci goto out_class_create_file_2_failed; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci return 0; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ciout_class_create_file_2_failed: 20638c2ecf20Sopenharmony_ci class_remove_file(zcrypt_class, &class_attr_zcdn_create); 20648c2ecf20Sopenharmony_ciout_class_create_file_1_failed: 20658c2ecf20Sopenharmony_ci cdev_del(&zcrypt_cdev); 20668c2ecf20Sopenharmony_ciout_cdev_add_failed: 20678c2ecf20Sopenharmony_ci unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES); 20688c2ecf20Sopenharmony_ciout_alloc_chrdev_failed: 20698c2ecf20Sopenharmony_ci class_destroy(zcrypt_class); 20708c2ecf20Sopenharmony_ciout_class_create_failed: 20718c2ecf20Sopenharmony_ci return rc; 20728c2ecf20Sopenharmony_ci} 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_cistatic void zcdn_exit(void) 20758c2ecf20Sopenharmony_ci{ 20768c2ecf20Sopenharmony_ci class_remove_file(zcrypt_class, &class_attr_zcdn_create); 20778c2ecf20Sopenharmony_ci class_remove_file(zcrypt_class, &class_attr_zcdn_destroy); 20788c2ecf20Sopenharmony_ci zcdn_destroy_all(); 20798c2ecf20Sopenharmony_ci cdev_del(&zcrypt_cdev); 20808c2ecf20Sopenharmony_ci unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES); 20818c2ecf20Sopenharmony_ci class_destroy(zcrypt_class); 20828c2ecf20Sopenharmony_ci} 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci#endif 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci/** 20878c2ecf20Sopenharmony_ci * zcrypt_api_init(): Module initialization. 20888c2ecf20Sopenharmony_ci * 20898c2ecf20Sopenharmony_ci * The module initialization code. 20908c2ecf20Sopenharmony_ci */ 20918c2ecf20Sopenharmony_ciint __init zcrypt_api_init(void) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci int rc; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci rc = zcrypt_debug_init(); 20968c2ecf20Sopenharmony_ci if (rc) 20978c2ecf20Sopenharmony_ci goto out; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 21008c2ecf20Sopenharmony_ci rc = zcdn_init(); 21018c2ecf20Sopenharmony_ci if (rc) 21028c2ecf20Sopenharmony_ci goto out; 21038c2ecf20Sopenharmony_ci#endif 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* Register the request sprayer. */ 21068c2ecf20Sopenharmony_ci rc = misc_register(&zcrypt_misc_device); 21078c2ecf20Sopenharmony_ci if (rc < 0) 21088c2ecf20Sopenharmony_ci goto out_misc_register_failed; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci zcrypt_msgtype6_init(); 21118c2ecf20Sopenharmony_ci zcrypt_msgtype50_init(); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci return 0; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ciout_misc_register_failed: 21168c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 21178c2ecf20Sopenharmony_ci zcdn_exit(); 21188c2ecf20Sopenharmony_ci#endif 21198c2ecf20Sopenharmony_ci zcrypt_debug_exit(); 21208c2ecf20Sopenharmony_ciout: 21218c2ecf20Sopenharmony_ci return rc; 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci/** 21258c2ecf20Sopenharmony_ci * zcrypt_api_exit(): Module termination. 21268c2ecf20Sopenharmony_ci * 21278c2ecf20Sopenharmony_ci * The module termination code. 21288c2ecf20Sopenharmony_ci */ 21298c2ecf20Sopenharmony_civoid __exit zcrypt_api_exit(void) 21308c2ecf20Sopenharmony_ci{ 21318c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_MULTIDEVNODES 21328c2ecf20Sopenharmony_ci zcdn_exit(); 21338c2ecf20Sopenharmony_ci#endif 21348c2ecf20Sopenharmony_ci misc_deregister(&zcrypt_misc_device); 21358c2ecf20Sopenharmony_ci zcrypt_msgtype6_exit(); 21368c2ecf20Sopenharmony_ci zcrypt_msgtype50_exit(); 21378c2ecf20Sopenharmony_ci zcrypt_ccamisc_exit(); 21388c2ecf20Sopenharmony_ci zcrypt_ep11misc_exit(); 21398c2ecf20Sopenharmony_ci zcrypt_debug_exit(); 21408c2ecf20Sopenharmony_ci} 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_cimodule_init(zcrypt_api_init); 21438c2ecf20Sopenharmony_cimodule_exit(zcrypt_api_exit); 2144