18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * S/390 common I/O routines -- blacklisting of specific devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2013 68c2ecf20Sopenharmony_ci * Author(s): Ingo Adlung (adlung@de.ibm.com) 78c2ecf20Sopenharmony_ci * Cornelia Huck (cornelia.huck@de.ibm.com) 88c2ecf20Sopenharmony_ci * Arnd Bergmann (arndb@de.ibm.com) 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "cio" 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 168c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 178c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 188c2ecf20Sopenharmony_ci#include <linux/ctype.h> 198c2ecf20Sopenharmony_ci#include <linux/device.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 228c2ecf20Sopenharmony_ci#include <asm/cio.h> 238c2ecf20Sopenharmony_ci#include <asm/ipl.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "blacklist.h" 268c2ecf20Sopenharmony_ci#include "cio.h" 278c2ecf20Sopenharmony_ci#include "cio_debug.h" 288c2ecf20Sopenharmony_ci#include "css.h" 298c2ecf20Sopenharmony_ci#include "device.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * "Blacklisting" of certain devices: 338c2ecf20Sopenharmony_ci * Device numbers given in the commandline as cio_ignore=... won't be known 348c2ecf20Sopenharmony_ci * to Linux. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * These can be single devices or ranges of devices 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 65536 bits for each set to indicate if a devno is blacklisted or not */ 408c2ecf20Sopenharmony_ci#define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \ 418c2ecf20Sopenharmony_ci (8*sizeof(long))) 428c2ecf20Sopenharmony_cistatic unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS]; 438c2ecf20Sopenharmony_citypedef enum {add, free} range_action; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Function: blacklist_range 478c2ecf20Sopenharmony_ci * (Un-)blacklist the devices from-to 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_cistatic int blacklist_range(range_action action, unsigned int from_ssid, 508c2ecf20Sopenharmony_ci unsigned int to_ssid, unsigned int from, 518c2ecf20Sopenharmony_ci unsigned int to, int msgtrigger) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { 548c2ecf20Sopenharmony_ci if (msgtrigger) 558c2ecf20Sopenharmony_ci pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n", 568c2ecf20Sopenharmony_ci from_ssid, from, to_ssid, to); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return 1; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) && 628c2ecf20Sopenharmony_ci (from <= to))) { 638c2ecf20Sopenharmony_ci if (action == add) 648c2ecf20Sopenharmony_ci set_bit(from, bl_dev[from_ssid]); 658c2ecf20Sopenharmony_ci else 668c2ecf20Sopenharmony_ci clear_bit(from, bl_dev[from_ssid]); 678c2ecf20Sopenharmony_ci from++; 688c2ecf20Sopenharmony_ci if (from > __MAX_SUBCHANNEL) { 698c2ecf20Sopenharmony_ci from_ssid++; 708c2ecf20Sopenharmony_ci from = 0; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int pure_hex(char **cp, unsigned int *val, int min_digit, 788c2ecf20Sopenharmony_ci int max_digit, int max_val) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int diff; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci diff = 0; 838c2ecf20Sopenharmony_ci *val = 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci while (diff <= max_digit) { 868c2ecf20Sopenharmony_ci int value = hex_to_bin(**cp); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (value < 0) 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci *val = *val * 16 + value; 918c2ecf20Sopenharmony_ci (*cp)++; 928c2ecf20Sopenharmony_ci diff++; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if ((diff < min_digit) || (diff > max_digit) || (*val > max_val)) 968c2ecf20Sopenharmony_ci return 1; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, 1028c2ecf20Sopenharmony_ci unsigned int *devno, int msgtrigger) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci char *str_work; 1058c2ecf20Sopenharmony_ci int val, rc, ret; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci rc = 1; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (*str == '\0') 1108c2ecf20Sopenharmony_ci goto out; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* old style */ 1138c2ecf20Sopenharmony_ci str_work = str; 1148c2ecf20Sopenharmony_ci val = simple_strtoul(str, &str_work, 16); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (*str_work == '\0') { 1178c2ecf20Sopenharmony_ci if (val <= __MAX_SUBCHANNEL) { 1188c2ecf20Sopenharmony_ci *devno = val; 1198c2ecf20Sopenharmony_ci *ssid = 0; 1208c2ecf20Sopenharmony_ci *cssid = 0; 1218c2ecf20Sopenharmony_ci rc = 0; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci goto out; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* new style */ 1278c2ecf20Sopenharmony_ci str_work = str; 1288c2ecf20Sopenharmony_ci ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID); 1298c2ecf20Sopenharmony_ci if (ret || (str_work[0] != '.')) 1308c2ecf20Sopenharmony_ci goto out; 1318c2ecf20Sopenharmony_ci str_work++; 1328c2ecf20Sopenharmony_ci ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID); 1338c2ecf20Sopenharmony_ci if (ret || (str_work[0] != '.')) 1348c2ecf20Sopenharmony_ci goto out; 1358c2ecf20Sopenharmony_ci str_work++; 1368c2ecf20Sopenharmony_ci ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL); 1378c2ecf20Sopenharmony_ci if (ret || (str_work[0] != '\0')) 1388c2ecf20Sopenharmony_ci goto out; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci rc = 0; 1418c2ecf20Sopenharmony_ciout: 1428c2ecf20Sopenharmony_ci if (rc && msgtrigger) 1438c2ecf20Sopenharmony_ci pr_warn("%s is not a valid device for the cio_ignore kernel parameter\n", 1448c2ecf20Sopenharmony_ci str); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return rc; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int blacklist_parse_parameters(char *str, range_action action, 1508c2ecf20Sopenharmony_ci int msgtrigger) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to; 1538c2ecf20Sopenharmony_ci int rc, totalrc; 1548c2ecf20Sopenharmony_ci char *parm; 1558c2ecf20Sopenharmony_ci range_action ra; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci totalrc = 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci while ((parm = strsep(&str, ","))) { 1608c2ecf20Sopenharmony_ci rc = 0; 1618c2ecf20Sopenharmony_ci ra = action; 1628c2ecf20Sopenharmony_ci if (*parm == '!') { 1638c2ecf20Sopenharmony_ci if (ra == add) 1648c2ecf20Sopenharmony_ci ra = free; 1658c2ecf20Sopenharmony_ci else 1668c2ecf20Sopenharmony_ci ra = add; 1678c2ecf20Sopenharmony_ci parm++; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (strcmp(parm, "all") == 0) { 1708c2ecf20Sopenharmony_ci from_cssid = 0; 1718c2ecf20Sopenharmony_ci from_ssid = 0; 1728c2ecf20Sopenharmony_ci from = 0; 1738c2ecf20Sopenharmony_ci to_cssid = __MAX_CSSID; 1748c2ecf20Sopenharmony_ci to_ssid = __MAX_SSID; 1758c2ecf20Sopenharmony_ci to = __MAX_SUBCHANNEL; 1768c2ecf20Sopenharmony_ci } else if (strcmp(parm, "ipldev") == 0) { 1778c2ecf20Sopenharmony_ci if (ipl_info.type == IPL_TYPE_CCW) { 1788c2ecf20Sopenharmony_ci from_cssid = 0; 1798c2ecf20Sopenharmony_ci from_ssid = ipl_info.data.ccw.dev_id.ssid; 1808c2ecf20Sopenharmony_ci from = ipl_info.data.ccw.dev_id.devno; 1818c2ecf20Sopenharmony_ci } else if (ipl_info.type == IPL_TYPE_FCP || 1828c2ecf20Sopenharmony_ci ipl_info.type == IPL_TYPE_FCP_DUMP) { 1838c2ecf20Sopenharmony_ci from_cssid = 0; 1848c2ecf20Sopenharmony_ci from_ssid = ipl_info.data.fcp.dev_id.ssid; 1858c2ecf20Sopenharmony_ci from = ipl_info.data.fcp.dev_id.devno; 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci continue; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci to_cssid = from_cssid; 1908c2ecf20Sopenharmony_ci to_ssid = from_ssid; 1918c2ecf20Sopenharmony_ci to = from; 1928c2ecf20Sopenharmony_ci } else if (strcmp(parm, "condev") == 0) { 1938c2ecf20Sopenharmony_ci if (console_devno == -1) 1948c2ecf20Sopenharmony_ci continue; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci from_cssid = to_cssid = 0; 1978c2ecf20Sopenharmony_ci from_ssid = to_ssid = 0; 1988c2ecf20Sopenharmony_ci from = to = console_devno; 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci rc = parse_busid(strsep(&parm, "-"), &from_cssid, 2018c2ecf20Sopenharmony_ci &from_ssid, &from, msgtrigger); 2028c2ecf20Sopenharmony_ci if (!rc) { 2038c2ecf20Sopenharmony_ci if (parm != NULL) 2048c2ecf20Sopenharmony_ci rc = parse_busid(parm, &to_cssid, 2058c2ecf20Sopenharmony_ci &to_ssid, &to, 2068c2ecf20Sopenharmony_ci msgtrigger); 2078c2ecf20Sopenharmony_ci else { 2088c2ecf20Sopenharmony_ci to_cssid = from_cssid; 2098c2ecf20Sopenharmony_ci to_ssid = from_ssid; 2108c2ecf20Sopenharmony_ci to = from; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci if (!rc) { 2158c2ecf20Sopenharmony_ci rc = blacklist_range(ra, from_ssid, to_ssid, from, to, 2168c2ecf20Sopenharmony_ci msgtrigger); 2178c2ecf20Sopenharmony_ci if (rc) 2188c2ecf20Sopenharmony_ci totalrc = -EINVAL; 2198c2ecf20Sopenharmony_ci } else 2208c2ecf20Sopenharmony_ci totalrc = -EINVAL; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return totalrc; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int __init 2278c2ecf20Sopenharmony_ciblacklist_setup (char *str) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci CIO_MSG_EVENT(6, "Reading blacklist parameters\n"); 2308c2ecf20Sopenharmony_ci if (blacklist_parse_parameters(str, add, 1)) 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci return 1; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci__setup ("cio_ignore=", blacklist_setup); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* Checking if devices are blacklisted */ 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * Function: is_blacklisted 2418c2ecf20Sopenharmony_ci * Returns 1 if the given devicenumber can be found in the blacklist, 2428c2ecf20Sopenharmony_ci * otherwise 0. 2438c2ecf20Sopenharmony_ci * Used by validate_subchannel() 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ciint 2468c2ecf20Sopenharmony_ciis_blacklisted (int ssid, int devno) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci return test_bit (devno, bl_dev[ssid]); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 2528c2ecf20Sopenharmony_ci/* 2538c2ecf20Sopenharmony_ci * Function: blacklist_parse_proc_parameters 2548c2ecf20Sopenharmony_ci * parse the stuff which is piped to /proc/cio_ignore 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_cistatic int blacklist_parse_proc_parameters(char *buf) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci int rc; 2598c2ecf20Sopenharmony_ci char *parm; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci parm = strsep(&buf, " "); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (strcmp("free", parm) == 0) { 2648c2ecf20Sopenharmony_ci rc = blacklist_parse_parameters(buf, free, 0); 2658c2ecf20Sopenharmony_ci css_schedule_eval_all_unreg(0); 2668c2ecf20Sopenharmony_ci } else if (strcmp("add", parm) == 0) 2678c2ecf20Sopenharmony_ci rc = blacklist_parse_parameters(buf, add, 0); 2688c2ecf20Sopenharmony_ci else if (strcmp("purge", parm) == 0) 2698c2ecf20Sopenharmony_ci return ccw_purge_blacklisted(); 2708c2ecf20Sopenharmony_ci else 2718c2ecf20Sopenharmony_ci return -EINVAL; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return rc; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* Iterator struct for all devices. */ 2788c2ecf20Sopenharmony_cistruct ccwdev_iter { 2798c2ecf20Sopenharmony_ci int devno; 2808c2ecf20Sopenharmony_ci int ssid; 2818c2ecf20Sopenharmony_ci int in_range; 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic void * 2858c2ecf20Sopenharmony_cicio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct ccwdev_iter *iter = s->private; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 2908c2ecf20Sopenharmony_ci return NULL; 2918c2ecf20Sopenharmony_ci memset(iter, 0, sizeof(*iter)); 2928c2ecf20Sopenharmony_ci iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); 2938c2ecf20Sopenharmony_ci iter->devno = *offset % (__MAX_SUBCHANNEL + 1); 2948c2ecf20Sopenharmony_ci return iter; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void 2988c2ecf20Sopenharmony_cicio_ignore_proc_seq_stop(struct seq_file *s, void *it) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void * 3038c2ecf20Sopenharmony_cicio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct ccwdev_iter *iter; 3068c2ecf20Sopenharmony_ci loff_t p = *offset; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci (*offset)++; 3098c2ecf20Sopenharmony_ci if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 3108c2ecf20Sopenharmony_ci return NULL; 3118c2ecf20Sopenharmony_ci iter = it; 3128c2ecf20Sopenharmony_ci if (iter->devno == __MAX_SUBCHANNEL) { 3138c2ecf20Sopenharmony_ci iter->devno = 0; 3148c2ecf20Sopenharmony_ci iter->ssid++; 3158c2ecf20Sopenharmony_ci if (iter->ssid > __MAX_SSID) 3168c2ecf20Sopenharmony_ci return NULL; 3178c2ecf20Sopenharmony_ci } else 3188c2ecf20Sopenharmony_ci iter->devno++; 3198c2ecf20Sopenharmony_ci return iter; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int 3238c2ecf20Sopenharmony_cicio_ignore_proc_seq_show(struct seq_file *s, void *it) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct ccwdev_iter *iter; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci iter = it; 3288c2ecf20Sopenharmony_ci if (!is_blacklisted(iter->ssid, iter->devno)) 3298c2ecf20Sopenharmony_ci /* Not blacklisted, nothing to output. */ 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci if (!iter->in_range) { 3328c2ecf20Sopenharmony_ci /* First device in range. */ 3338c2ecf20Sopenharmony_ci if ((iter->devno == __MAX_SUBCHANNEL) || 3348c2ecf20Sopenharmony_ci !is_blacklisted(iter->ssid, iter->devno + 1)) { 3358c2ecf20Sopenharmony_ci /* Singular device. */ 3368c2ecf20Sopenharmony_ci seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci iter->in_range = 1; 3408c2ecf20Sopenharmony_ci seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci if ((iter->devno == __MAX_SUBCHANNEL) || 3448c2ecf20Sopenharmony_ci !is_blacklisted(iter->ssid, iter->devno + 1)) { 3458c2ecf20Sopenharmony_ci /* Last device in range. */ 3468c2ecf20Sopenharmony_ci iter->in_range = 0; 3478c2ecf20Sopenharmony_ci seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic ssize_t 3538c2ecf20Sopenharmony_cicio_ignore_write(struct file *file, const char __user *user_buf, 3548c2ecf20Sopenharmony_ci size_t user_len, loff_t *offset) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci char *buf; 3578c2ecf20Sopenharmony_ci ssize_t rc, ret, i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (*offset) 3608c2ecf20Sopenharmony_ci return -EINVAL; 3618c2ecf20Sopenharmony_ci if (user_len > 65536) 3628c2ecf20Sopenharmony_ci user_len = 65536; 3638c2ecf20Sopenharmony_ci buf = vzalloc(user_len + 1); /* maybe better use the stack? */ 3648c2ecf20Sopenharmony_ci if (buf == NULL) 3658c2ecf20Sopenharmony_ci return -ENOMEM; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (strncpy_from_user (buf, user_buf, user_len) < 0) { 3688c2ecf20Sopenharmony_ci rc = -EFAULT; 3698c2ecf20Sopenharmony_ci goto out_free; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci i = user_len - 1; 3738c2ecf20Sopenharmony_ci while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) { 3748c2ecf20Sopenharmony_ci buf[i] = '\0'; 3758c2ecf20Sopenharmony_ci i--; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci ret = blacklist_parse_proc_parameters(buf); 3788c2ecf20Sopenharmony_ci if (ret) 3798c2ecf20Sopenharmony_ci rc = ret; 3808c2ecf20Sopenharmony_ci else 3818c2ecf20Sopenharmony_ci rc = user_len; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ciout_free: 3848c2ecf20Sopenharmony_ci vfree (buf); 3858c2ecf20Sopenharmony_ci return rc; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic const struct seq_operations cio_ignore_proc_seq_ops = { 3898c2ecf20Sopenharmony_ci .start = cio_ignore_proc_seq_start, 3908c2ecf20Sopenharmony_ci .stop = cio_ignore_proc_seq_stop, 3918c2ecf20Sopenharmony_ci .next = cio_ignore_proc_seq_next, 3928c2ecf20Sopenharmony_ci .show = cio_ignore_proc_seq_show, 3938c2ecf20Sopenharmony_ci}; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int 3968c2ecf20Sopenharmony_cicio_ignore_proc_open(struct inode *inode, struct file *file) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci return seq_open_private(file, &cio_ignore_proc_seq_ops, 3998c2ecf20Sopenharmony_ci sizeof(struct ccwdev_iter)); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic const struct proc_ops cio_ignore_proc_ops = { 4038c2ecf20Sopenharmony_ci .proc_open = cio_ignore_proc_open, 4048c2ecf20Sopenharmony_ci .proc_read = seq_read, 4058c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 4068c2ecf20Sopenharmony_ci .proc_release = seq_release_private, 4078c2ecf20Sopenharmony_ci .proc_write = cio_ignore_write, 4088c2ecf20Sopenharmony_ci}; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int 4118c2ecf20Sopenharmony_cicio_ignore_proc_init (void) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct proc_dir_entry *entry; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, 4168c2ecf20Sopenharmony_ci &cio_ignore_proc_ops); 4178c2ecf20Sopenharmony_ci if (!entry) 4188c2ecf20Sopenharmony_ci return -ENOENT; 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci__initcall (cio_ignore_proc_init); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 425