1*a4f17cc7SVineeth Vijayan // SPDX-License-Identifier: GPL-2.0 2*a4f17cc7SVineeth Vijayan /* 3*a4f17cc7SVineeth Vijayan * CIO inject interface 4*a4f17cc7SVineeth Vijayan * 5*a4f17cc7SVineeth Vijayan * Copyright IBM Corp. 2021 6*a4f17cc7SVineeth Vijayan * Author(s): Vineeth Vijayan <vneethv@linux.ibm.com> 7*a4f17cc7SVineeth Vijayan */ 8*a4f17cc7SVineeth Vijayan 9*a4f17cc7SVineeth Vijayan #define KMSG_COMPONENT "cio" 10*a4f17cc7SVineeth Vijayan #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 11*a4f17cc7SVineeth Vijayan 12*a4f17cc7SVineeth Vijayan #include <linux/slab.h> 13*a4f17cc7SVineeth Vijayan #include <linux/spinlock.h> 14*a4f17cc7SVineeth Vijayan #include <linux/mm.h> 15*a4f17cc7SVineeth Vijayan #include <linux/debugfs.h> 16*a4f17cc7SVineeth Vijayan #include <asm/chpid.h> 17*a4f17cc7SVineeth Vijayan 18*a4f17cc7SVineeth Vijayan #include "cio_inject.h" 19*a4f17cc7SVineeth Vijayan #include "cio_debug.h" 20*a4f17cc7SVineeth Vijayan 21*a4f17cc7SVineeth Vijayan static DEFINE_SPINLOCK(crw_inject_lock); 22*a4f17cc7SVineeth Vijayan DEFINE_STATIC_KEY_FALSE(cio_inject_enabled); 23*a4f17cc7SVineeth Vijayan static struct crw *crw_inject_data; 24*a4f17cc7SVineeth Vijayan 25*a4f17cc7SVineeth Vijayan /** 26*a4f17cc7SVineeth Vijayan * crw_inject : Initiate the artificial CRW inject 27*a4f17cc7SVineeth Vijayan * @crw: The data which needs to be injected as new CRW. 28*a4f17cc7SVineeth Vijayan * 29*a4f17cc7SVineeth Vijayan * The CRW handler is called, which will use the provided artificial 30*a4f17cc7SVineeth Vijayan * data instead of the CRW from the underlying hardware. 31*a4f17cc7SVineeth Vijayan * 32*a4f17cc7SVineeth Vijayan * Return: 0 on success 33*a4f17cc7SVineeth Vijayan */ 34*a4f17cc7SVineeth Vijayan static int crw_inject(struct crw *crw) 35*a4f17cc7SVineeth Vijayan { 36*a4f17cc7SVineeth Vijayan int rc = 0; 37*a4f17cc7SVineeth Vijayan struct crw *copy; 38*a4f17cc7SVineeth Vijayan unsigned long flags; 39*a4f17cc7SVineeth Vijayan 40*a4f17cc7SVineeth Vijayan copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL); 41*a4f17cc7SVineeth Vijayan if (!copy) 42*a4f17cc7SVineeth Vijayan return -ENOMEM; 43*a4f17cc7SVineeth Vijayan 44*a4f17cc7SVineeth Vijayan spin_lock_irqsave(&crw_inject_lock, flags); 45*a4f17cc7SVineeth Vijayan if (crw_inject_data) { 46*a4f17cc7SVineeth Vijayan kfree(copy); 47*a4f17cc7SVineeth Vijayan rc = -EBUSY; 48*a4f17cc7SVineeth Vijayan } else { 49*a4f17cc7SVineeth Vijayan crw_inject_data = copy; 50*a4f17cc7SVineeth Vijayan } 51*a4f17cc7SVineeth Vijayan spin_unlock_irqrestore(&crw_inject_lock, flags); 52*a4f17cc7SVineeth Vijayan 53*a4f17cc7SVineeth Vijayan if (!rc) 54*a4f17cc7SVineeth Vijayan crw_handle_channel_report(); 55*a4f17cc7SVineeth Vijayan 56*a4f17cc7SVineeth Vijayan return rc; 57*a4f17cc7SVineeth Vijayan } 58*a4f17cc7SVineeth Vijayan 59*a4f17cc7SVineeth Vijayan /** 60*a4f17cc7SVineeth Vijayan * stcrw_get_injected: Copy the artificial CRW data to CRW struct. 61*a4f17cc7SVineeth Vijayan * @crw: The target CRW pointer. 62*a4f17cc7SVineeth Vijayan * 63*a4f17cc7SVineeth Vijayan * Retrieve an injected CRW data. Return 0 on success, 1 if no 64*a4f17cc7SVineeth Vijayan * injected-CRW is available. The function reproduces the return 65*a4f17cc7SVineeth Vijayan * code of the actual STCRW function. 66*a4f17cc7SVineeth Vijayan */ 67*a4f17cc7SVineeth Vijayan int stcrw_get_injected(struct crw *crw) 68*a4f17cc7SVineeth Vijayan { 69*a4f17cc7SVineeth Vijayan int rc = 1; 70*a4f17cc7SVineeth Vijayan unsigned long flags; 71*a4f17cc7SVineeth Vijayan 72*a4f17cc7SVineeth Vijayan spin_lock_irqsave(&crw_inject_lock, flags); 73*a4f17cc7SVineeth Vijayan if (crw_inject_data) { 74*a4f17cc7SVineeth Vijayan memcpy(crw, crw_inject_data, sizeof(*crw)); 75*a4f17cc7SVineeth Vijayan kfree(crw_inject_data); 76*a4f17cc7SVineeth Vijayan crw_inject_data = NULL; 77*a4f17cc7SVineeth Vijayan rc = 0; 78*a4f17cc7SVineeth Vijayan } 79*a4f17cc7SVineeth Vijayan spin_unlock_irqrestore(&crw_inject_lock, flags); 80*a4f17cc7SVineeth Vijayan 81*a4f17cc7SVineeth Vijayan return rc; 82*a4f17cc7SVineeth Vijayan } 83*a4f17cc7SVineeth Vijayan 84*a4f17cc7SVineeth Vijayan /* The debugfs write handler for crw_inject nodes operation */ 85*a4f17cc7SVineeth Vijayan static ssize_t crw_inject_write(struct file *file, const char __user *buf, 86*a4f17cc7SVineeth Vijayan size_t lbuf, loff_t *ppos) 87*a4f17cc7SVineeth Vijayan { 88*a4f17cc7SVineeth Vijayan u32 slct, oflw, chn, rsc, anc, erc, rsid; 89*a4f17cc7SVineeth Vijayan struct crw crw; 90*a4f17cc7SVineeth Vijayan char *buffer; 91*a4f17cc7SVineeth Vijayan int rc; 92*a4f17cc7SVineeth Vijayan 93*a4f17cc7SVineeth Vijayan if (!static_branch_likely(&cio_inject_enabled)) { 94*a4f17cc7SVineeth Vijayan pr_warn("CIO inject is not enabled - ignoring CRW inject\n"); 95*a4f17cc7SVineeth Vijayan return -EINVAL; 96*a4f17cc7SVineeth Vijayan } 97*a4f17cc7SVineeth Vijayan 98*a4f17cc7SVineeth Vijayan buffer = vmemdup_user(buf, lbuf); 99*a4f17cc7SVineeth Vijayan if (IS_ERR(buffer)) 100*a4f17cc7SVineeth Vijayan return -ENOMEM; 101*a4f17cc7SVineeth Vijayan 102*a4f17cc7SVineeth Vijayan rc = sscanf(buffer, "%x %x %x %x %x %x %x", &slct, &oflw, &chn, &rsc, &anc, 103*a4f17cc7SVineeth Vijayan &erc, &rsid); 104*a4f17cc7SVineeth Vijayan 105*a4f17cc7SVineeth Vijayan kvfree(buffer); 106*a4f17cc7SVineeth Vijayan if (rc != 7) { 107*a4f17cc7SVineeth Vijayan pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n"); 108*a4f17cc7SVineeth Vijayan return -EINVAL; 109*a4f17cc7SVineeth Vijayan } 110*a4f17cc7SVineeth Vijayan 111*a4f17cc7SVineeth Vijayan memset(&crw, 0, sizeof(crw)); 112*a4f17cc7SVineeth Vijayan crw.slct = slct; 113*a4f17cc7SVineeth Vijayan crw.oflw = oflw; 114*a4f17cc7SVineeth Vijayan crw.chn = chn; 115*a4f17cc7SVineeth Vijayan crw.rsc = rsc; 116*a4f17cc7SVineeth Vijayan crw.anc = anc; 117*a4f17cc7SVineeth Vijayan crw.erc = erc; 118*a4f17cc7SVineeth Vijayan crw.rsid = rsid; 119*a4f17cc7SVineeth Vijayan 120*a4f17cc7SVineeth Vijayan rc = crw_inject(&crw); 121*a4f17cc7SVineeth Vijayan if (rc) 122*a4f17cc7SVineeth Vijayan return rc; 123*a4f17cc7SVineeth Vijayan 124*a4f17cc7SVineeth Vijayan return lbuf; 125*a4f17cc7SVineeth Vijayan } 126*a4f17cc7SVineeth Vijayan 127*a4f17cc7SVineeth Vijayan /* Debugfs write handler for inject_enable node*/ 128*a4f17cc7SVineeth Vijayan static ssize_t enable_inject_write(struct file *file, const char __user *buf, 129*a4f17cc7SVineeth Vijayan size_t lbuf, loff_t *ppos) 130*a4f17cc7SVineeth Vijayan { 131*a4f17cc7SVineeth Vijayan unsigned long en = 0; 132*a4f17cc7SVineeth Vijayan int rc; 133*a4f17cc7SVineeth Vijayan 134*a4f17cc7SVineeth Vijayan rc = kstrtoul_from_user(buf, lbuf, 10, &en); 135*a4f17cc7SVineeth Vijayan if (rc) 136*a4f17cc7SVineeth Vijayan return rc; 137*a4f17cc7SVineeth Vijayan 138*a4f17cc7SVineeth Vijayan switch (en) { 139*a4f17cc7SVineeth Vijayan case 0: 140*a4f17cc7SVineeth Vijayan static_branch_disable(&cio_inject_enabled); 141*a4f17cc7SVineeth Vijayan break; 142*a4f17cc7SVineeth Vijayan case 1: 143*a4f17cc7SVineeth Vijayan static_branch_enable(&cio_inject_enabled); 144*a4f17cc7SVineeth Vijayan break; 145*a4f17cc7SVineeth Vijayan } 146*a4f17cc7SVineeth Vijayan 147*a4f17cc7SVineeth Vijayan return lbuf; 148*a4f17cc7SVineeth Vijayan } 149*a4f17cc7SVineeth Vijayan 150*a4f17cc7SVineeth Vijayan static const struct file_operations crw_fops = { 151*a4f17cc7SVineeth Vijayan .owner = THIS_MODULE, 152*a4f17cc7SVineeth Vijayan .write = crw_inject_write, 153*a4f17cc7SVineeth Vijayan }; 154*a4f17cc7SVineeth Vijayan 155*a4f17cc7SVineeth Vijayan static const struct file_operations cio_en_fops = { 156*a4f17cc7SVineeth Vijayan .owner = THIS_MODULE, 157*a4f17cc7SVineeth Vijayan .write = enable_inject_write, 158*a4f17cc7SVineeth Vijayan }; 159*a4f17cc7SVineeth Vijayan 160*a4f17cc7SVineeth Vijayan static int __init cio_inject_init(void) 161*a4f17cc7SVineeth Vijayan { 162*a4f17cc7SVineeth Vijayan /* enable_inject node enables the static branching */ 163*a4f17cc7SVineeth Vijayan debugfs_create_file("enable_inject", 0200, cio_debugfs_dir, 164*a4f17cc7SVineeth Vijayan NULL, &cio_en_fops); 165*a4f17cc7SVineeth Vijayan 166*a4f17cc7SVineeth Vijayan debugfs_create_file("crw_inject", 0200, cio_debugfs_dir, 167*a4f17cc7SVineeth Vijayan NULL, &crw_fops); 168*a4f17cc7SVineeth Vijayan return 0; 169*a4f17cc7SVineeth Vijayan } 170*a4f17cc7SVineeth Vijayan 171*a4f17cc7SVineeth Vijayan device_initcall(cio_inject_init); 172