162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * S/390 common I/O routines -- blacklisting of specific devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright IBM Corp. 1999, 2013 662306a36Sopenharmony_ci * Author(s): Ingo Adlung (adlung@de.ibm.com) 762306a36Sopenharmony_ci * Cornelia Huck (cornelia.huck@de.ibm.com) 862306a36Sopenharmony_ci * Arnd Bergmann (arndb@de.ibm.com) 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define KMSG_COMPONENT "cio" 1262306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/vmalloc.h> 1662306a36Sopenharmony_ci#include <linux/proc_fs.h> 1762306a36Sopenharmony_ci#include <linux/seq_file.h> 1862306a36Sopenharmony_ci#include <linux/ctype.h> 1962306a36Sopenharmony_ci#include <linux/device.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/uaccess.h> 2262306a36Sopenharmony_ci#include <asm/cio.h> 2362306a36Sopenharmony_ci#include <asm/ipl.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "blacklist.h" 2662306a36Sopenharmony_ci#include "cio.h" 2762306a36Sopenharmony_ci#include "cio_debug.h" 2862306a36Sopenharmony_ci#include "css.h" 2962306a36Sopenharmony_ci#include "device.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * "Blacklisting" of certain devices: 3362306a36Sopenharmony_ci * Device numbers given in the commandline as cio_ignore=... won't be known 3462306a36Sopenharmony_ci * to Linux. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * These can be single devices or ranges of devices 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 65536 bits for each set to indicate if a devno is blacklisted or not */ 4062306a36Sopenharmony_ci#define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \ 4162306a36Sopenharmony_ci (8*sizeof(long))) 4262306a36Sopenharmony_cistatic unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS]; 4362306a36Sopenharmony_citypedef enum {add, free} range_action; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Function: blacklist_range 4762306a36Sopenharmony_ci * (Un-)blacklist the devices from-to 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cistatic int blacklist_range(range_action action, unsigned int from_ssid, 5062306a36Sopenharmony_ci unsigned int to_ssid, unsigned int from, 5162306a36Sopenharmony_ci unsigned int to, int msgtrigger) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { 5462306a36Sopenharmony_ci if (msgtrigger) 5562306a36Sopenharmony_ci pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n", 5662306a36Sopenharmony_ci from_ssid, from, to_ssid, to); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return 1; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) && 6262306a36Sopenharmony_ci (from <= to))) { 6362306a36Sopenharmony_ci if (action == add) 6462306a36Sopenharmony_ci set_bit(from, bl_dev[from_ssid]); 6562306a36Sopenharmony_ci else 6662306a36Sopenharmony_ci clear_bit(from, bl_dev[from_ssid]); 6762306a36Sopenharmony_ci from++; 6862306a36Sopenharmony_ci if (from > __MAX_SUBCHANNEL) { 6962306a36Sopenharmony_ci from_ssid++; 7062306a36Sopenharmony_ci from = 0; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int pure_hex(char **cp, unsigned int *val, int min_digit, 7862306a36Sopenharmony_ci int max_digit, int max_val) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci int diff; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci diff = 0; 8362306a36Sopenharmony_ci *val = 0; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci while (diff <= max_digit) { 8662306a36Sopenharmony_ci int value = hex_to_bin(**cp); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (value < 0) 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci *val = *val * 16 + value; 9162306a36Sopenharmony_ci (*cp)++; 9262306a36Sopenharmony_ci diff++; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if ((diff < min_digit) || (diff > max_digit) || (*val > max_val)) 9662306a36Sopenharmony_ci return 1; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, 10262306a36Sopenharmony_ci unsigned int *devno, int msgtrigger) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci char *str_work; 10562306a36Sopenharmony_ci int val, rc, ret; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci rc = 1; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (*str == '\0') 11062306a36Sopenharmony_ci goto out; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* old style */ 11362306a36Sopenharmony_ci str_work = str; 11462306a36Sopenharmony_ci val = simple_strtoul(str, &str_work, 16); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (*str_work == '\0') { 11762306a36Sopenharmony_ci if (val <= __MAX_SUBCHANNEL) { 11862306a36Sopenharmony_ci *devno = val; 11962306a36Sopenharmony_ci *ssid = 0; 12062306a36Sopenharmony_ci *cssid = 0; 12162306a36Sopenharmony_ci rc = 0; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci goto out; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* new style */ 12762306a36Sopenharmony_ci str_work = str; 12862306a36Sopenharmony_ci ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID); 12962306a36Sopenharmony_ci if (ret || (str_work[0] != '.')) 13062306a36Sopenharmony_ci goto out; 13162306a36Sopenharmony_ci str_work++; 13262306a36Sopenharmony_ci ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID); 13362306a36Sopenharmony_ci if (ret || (str_work[0] != '.')) 13462306a36Sopenharmony_ci goto out; 13562306a36Sopenharmony_ci str_work++; 13662306a36Sopenharmony_ci ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL); 13762306a36Sopenharmony_ci if (ret || (str_work[0] != '\0')) 13862306a36Sopenharmony_ci goto out; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci rc = 0; 14162306a36Sopenharmony_ciout: 14262306a36Sopenharmony_ci if (rc && msgtrigger) 14362306a36Sopenharmony_ci pr_warn("%s is not a valid device for the cio_ignore kernel parameter\n", 14462306a36Sopenharmony_ci str); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return rc; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int blacklist_parse_parameters(char *str, range_action action, 15062306a36Sopenharmony_ci int msgtrigger) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to; 15362306a36Sopenharmony_ci int rc, totalrc; 15462306a36Sopenharmony_ci char *parm; 15562306a36Sopenharmony_ci range_action ra; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci totalrc = 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci while ((parm = strsep(&str, ","))) { 16062306a36Sopenharmony_ci rc = 0; 16162306a36Sopenharmony_ci ra = action; 16262306a36Sopenharmony_ci if (*parm == '!') { 16362306a36Sopenharmony_ci if (ra == add) 16462306a36Sopenharmony_ci ra = free; 16562306a36Sopenharmony_ci else 16662306a36Sopenharmony_ci ra = add; 16762306a36Sopenharmony_ci parm++; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci if (strcmp(parm, "all") == 0) { 17062306a36Sopenharmony_ci from_cssid = 0; 17162306a36Sopenharmony_ci from_ssid = 0; 17262306a36Sopenharmony_ci from = 0; 17362306a36Sopenharmony_ci to_cssid = __MAX_CSSID; 17462306a36Sopenharmony_ci to_ssid = __MAX_SSID; 17562306a36Sopenharmony_ci to = __MAX_SUBCHANNEL; 17662306a36Sopenharmony_ci } else if (strcmp(parm, "ipldev") == 0) { 17762306a36Sopenharmony_ci if (ipl_info.type == IPL_TYPE_CCW) { 17862306a36Sopenharmony_ci from_cssid = 0; 17962306a36Sopenharmony_ci from_ssid = ipl_info.data.ccw.dev_id.ssid; 18062306a36Sopenharmony_ci from = ipl_info.data.ccw.dev_id.devno; 18162306a36Sopenharmony_ci } else if (ipl_info.type == IPL_TYPE_FCP || 18262306a36Sopenharmony_ci ipl_info.type == IPL_TYPE_FCP_DUMP) { 18362306a36Sopenharmony_ci from_cssid = 0; 18462306a36Sopenharmony_ci from_ssid = ipl_info.data.fcp.dev_id.ssid; 18562306a36Sopenharmony_ci from = ipl_info.data.fcp.dev_id.devno; 18662306a36Sopenharmony_ci } else { 18762306a36Sopenharmony_ci continue; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci to_cssid = from_cssid; 19062306a36Sopenharmony_ci to_ssid = from_ssid; 19162306a36Sopenharmony_ci to = from; 19262306a36Sopenharmony_ci } else if (strcmp(parm, "condev") == 0) { 19362306a36Sopenharmony_ci if (console_devno == -1) 19462306a36Sopenharmony_ci continue; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci from_cssid = to_cssid = 0; 19762306a36Sopenharmony_ci from_ssid = to_ssid = 0; 19862306a36Sopenharmony_ci from = to = console_devno; 19962306a36Sopenharmony_ci } else { 20062306a36Sopenharmony_ci rc = parse_busid(strsep(&parm, "-"), &from_cssid, 20162306a36Sopenharmony_ci &from_ssid, &from, msgtrigger); 20262306a36Sopenharmony_ci if (!rc) { 20362306a36Sopenharmony_ci if (parm != NULL) 20462306a36Sopenharmony_ci rc = parse_busid(parm, &to_cssid, 20562306a36Sopenharmony_ci &to_ssid, &to, 20662306a36Sopenharmony_ci msgtrigger); 20762306a36Sopenharmony_ci else { 20862306a36Sopenharmony_ci to_cssid = from_cssid; 20962306a36Sopenharmony_ci to_ssid = from_ssid; 21062306a36Sopenharmony_ci to = from; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci if (!rc) { 21562306a36Sopenharmony_ci rc = blacklist_range(ra, from_ssid, to_ssid, from, to, 21662306a36Sopenharmony_ci msgtrigger); 21762306a36Sopenharmony_ci if (rc) 21862306a36Sopenharmony_ci totalrc = -EINVAL; 21962306a36Sopenharmony_ci } else 22062306a36Sopenharmony_ci totalrc = -EINVAL; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return totalrc; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int __init 22762306a36Sopenharmony_ciblacklist_setup (char *str) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci CIO_MSG_EVENT(6, "Reading blacklist parameters\n"); 23062306a36Sopenharmony_ci if (blacklist_parse_parameters(str, add, 1)) 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci return 1; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci__setup ("cio_ignore=", blacklist_setup); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* Checking if devices are blacklisted */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* 24062306a36Sopenharmony_ci * Function: is_blacklisted 24162306a36Sopenharmony_ci * Returns 1 if the given devicenumber can be found in the blacklist, 24262306a36Sopenharmony_ci * otherwise 0. 24362306a36Sopenharmony_ci * Used by validate_subchannel() 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ciint 24662306a36Sopenharmony_ciis_blacklisted (int ssid, int devno) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci return test_bit (devno, bl_dev[ssid]); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 25262306a36Sopenharmony_ci/* 25362306a36Sopenharmony_ci * Function: blacklist_parse_proc_parameters 25462306a36Sopenharmony_ci * parse the stuff which is piped to /proc/cio_ignore 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_cistatic int blacklist_parse_proc_parameters(char *buf) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci int rc; 25962306a36Sopenharmony_ci char *parm; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci parm = strsep(&buf, " "); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (strcmp("free", parm) == 0) { 26462306a36Sopenharmony_ci rc = blacklist_parse_parameters(buf, free, 0); 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * Evaluate the subchannels without an online device. This way, 26762306a36Sopenharmony_ci * no path-verification will be triggered on those subchannels 26862306a36Sopenharmony_ci * and it avoids unnecessary delays. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci css_schedule_eval_cond(CSS_EVAL_NOT_ONLINE, 0); 27162306a36Sopenharmony_ci } else if (strcmp("add", parm) == 0) 27262306a36Sopenharmony_ci rc = blacklist_parse_parameters(buf, add, 0); 27362306a36Sopenharmony_ci else if (strcmp("purge", parm) == 0) 27462306a36Sopenharmony_ci return ccw_purge_blacklisted(); 27562306a36Sopenharmony_ci else 27662306a36Sopenharmony_ci return -EINVAL; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return rc; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* Iterator struct for all devices. */ 28362306a36Sopenharmony_cistruct ccwdev_iter { 28462306a36Sopenharmony_ci int devno; 28562306a36Sopenharmony_ci int ssid; 28662306a36Sopenharmony_ci int in_range; 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void * 29062306a36Sopenharmony_cicio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct ccwdev_iter *iter = s->private; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 29562306a36Sopenharmony_ci return NULL; 29662306a36Sopenharmony_ci memset(iter, 0, sizeof(*iter)); 29762306a36Sopenharmony_ci iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); 29862306a36Sopenharmony_ci iter->devno = *offset % (__MAX_SUBCHANNEL + 1); 29962306a36Sopenharmony_ci return iter; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void 30362306a36Sopenharmony_cicio_ignore_proc_seq_stop(struct seq_file *s, void *it) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void * 30862306a36Sopenharmony_cicio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct ccwdev_iter *iter; 31162306a36Sopenharmony_ci loff_t p = *offset; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci (*offset)++; 31462306a36Sopenharmony_ci if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 31562306a36Sopenharmony_ci return NULL; 31662306a36Sopenharmony_ci iter = it; 31762306a36Sopenharmony_ci if (iter->devno == __MAX_SUBCHANNEL) { 31862306a36Sopenharmony_ci iter->devno = 0; 31962306a36Sopenharmony_ci iter->ssid++; 32062306a36Sopenharmony_ci if (iter->ssid > __MAX_SSID) 32162306a36Sopenharmony_ci return NULL; 32262306a36Sopenharmony_ci } else 32362306a36Sopenharmony_ci iter->devno++; 32462306a36Sopenharmony_ci return iter; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int 32862306a36Sopenharmony_cicio_ignore_proc_seq_show(struct seq_file *s, void *it) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct ccwdev_iter *iter; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci iter = it; 33362306a36Sopenharmony_ci if (!is_blacklisted(iter->ssid, iter->devno)) 33462306a36Sopenharmony_ci /* Not blacklisted, nothing to output. */ 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci if (!iter->in_range) { 33762306a36Sopenharmony_ci /* First device in range. */ 33862306a36Sopenharmony_ci if ((iter->devno == __MAX_SUBCHANNEL) || 33962306a36Sopenharmony_ci !is_blacklisted(iter->ssid, iter->devno + 1)) { 34062306a36Sopenharmony_ci /* Singular device. */ 34162306a36Sopenharmony_ci seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci iter->in_range = 1; 34562306a36Sopenharmony_ci seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci if ((iter->devno == __MAX_SUBCHANNEL) || 34962306a36Sopenharmony_ci !is_blacklisted(iter->ssid, iter->devno + 1)) { 35062306a36Sopenharmony_ci /* Last device in range. */ 35162306a36Sopenharmony_ci iter->in_range = 0; 35262306a36Sopenharmony_ci seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic ssize_t 35862306a36Sopenharmony_cicio_ignore_write(struct file *file, const char __user *user_buf, 35962306a36Sopenharmony_ci size_t user_len, loff_t *offset) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci char *buf; 36262306a36Sopenharmony_ci ssize_t rc, ret, i; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (*offset) 36562306a36Sopenharmony_ci return -EINVAL; 36662306a36Sopenharmony_ci if (user_len > 65536) 36762306a36Sopenharmony_ci user_len = 65536; 36862306a36Sopenharmony_ci buf = vzalloc(user_len + 1); /* maybe better use the stack? */ 36962306a36Sopenharmony_ci if (buf == NULL) 37062306a36Sopenharmony_ci return -ENOMEM; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (strncpy_from_user (buf, user_buf, user_len) < 0) { 37362306a36Sopenharmony_ci rc = -EFAULT; 37462306a36Sopenharmony_ci goto out_free; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci i = user_len - 1; 37862306a36Sopenharmony_ci while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) { 37962306a36Sopenharmony_ci buf[i] = '\0'; 38062306a36Sopenharmony_ci i--; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci ret = blacklist_parse_proc_parameters(buf); 38362306a36Sopenharmony_ci if (ret) 38462306a36Sopenharmony_ci rc = ret; 38562306a36Sopenharmony_ci else 38662306a36Sopenharmony_ci rc = user_len; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ciout_free: 38962306a36Sopenharmony_ci vfree (buf); 39062306a36Sopenharmony_ci return rc; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic const struct seq_operations cio_ignore_proc_seq_ops = { 39462306a36Sopenharmony_ci .start = cio_ignore_proc_seq_start, 39562306a36Sopenharmony_ci .stop = cio_ignore_proc_seq_stop, 39662306a36Sopenharmony_ci .next = cio_ignore_proc_seq_next, 39762306a36Sopenharmony_ci .show = cio_ignore_proc_seq_show, 39862306a36Sopenharmony_ci}; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int 40162306a36Sopenharmony_cicio_ignore_proc_open(struct inode *inode, struct file *file) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci return seq_open_private(file, &cio_ignore_proc_seq_ops, 40462306a36Sopenharmony_ci sizeof(struct ccwdev_iter)); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic const struct proc_ops cio_ignore_proc_ops = { 40862306a36Sopenharmony_ci .proc_open = cio_ignore_proc_open, 40962306a36Sopenharmony_ci .proc_read = seq_read, 41062306a36Sopenharmony_ci .proc_lseek = seq_lseek, 41162306a36Sopenharmony_ci .proc_release = seq_release_private, 41262306a36Sopenharmony_ci .proc_write = cio_ignore_write, 41362306a36Sopenharmony_ci}; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int 41662306a36Sopenharmony_cicio_ignore_proc_init (void) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct proc_dir_entry *entry; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, 42162306a36Sopenharmony_ci &cio_ignore_proc_ops); 42262306a36Sopenharmony_ci if (!entry) 42362306a36Sopenharmony_ci return -ENOENT; 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci__initcall (cio_ignore_proc_init); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 430