18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
48c2ecf20Sopenharmony_ci *		    Horst Hummel <Horst.Hummel@de.ibm.com>
58c2ecf20Sopenharmony_ci *		    Carsten Otte <Cotte@de.ibm.com>
68c2ecf20Sopenharmony_ci *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
78c2ecf20Sopenharmony_ci * Bugreports.to..: <Linux390@de.ibm.com>
88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2002
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * /proc interface for the dasd driver.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "dasd"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/ctype.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/string.h>
198c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
208c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
218c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <asm/debug.h>
248c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* This is ugly... */
278c2ecf20Sopenharmony_ci#define PRINTK_HEADER "dasd_proc:"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "dasd_int.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic struct proc_dir_entry *dasd_proc_root_entry = NULL;
328c2ecf20Sopenharmony_cistatic struct proc_dir_entry *dasd_devices_entry = NULL;
338c2ecf20Sopenharmony_cistatic struct proc_dir_entry *dasd_statistics_entry = NULL;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int
368c2ecf20Sopenharmony_cidasd_devices_show(struct seq_file *m, void *v)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct dasd_device *device;
398c2ecf20Sopenharmony_ci	struct dasd_block *block;
408c2ecf20Sopenharmony_ci	char *substr;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	device = dasd_device_from_devindex((unsigned long) v - 1);
438c2ecf20Sopenharmony_ci	if (IS_ERR(device))
448c2ecf20Sopenharmony_ci		return 0;
458c2ecf20Sopenharmony_ci	if (device->block)
468c2ecf20Sopenharmony_ci		block = device->block;
478c2ecf20Sopenharmony_ci	else {
488c2ecf20Sopenharmony_ci		dasd_put_device(device);
498c2ecf20Sopenharmony_ci		return 0;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci	/* Print device number. */
528c2ecf20Sopenharmony_ci	seq_printf(m, "%s", dev_name(&device->cdev->dev));
538c2ecf20Sopenharmony_ci	/* Print discipline string. */
548c2ecf20Sopenharmony_ci	if (device->discipline != NULL)
558c2ecf20Sopenharmony_ci		seq_printf(m, "(%s)", device->discipline->name);
568c2ecf20Sopenharmony_ci	else
578c2ecf20Sopenharmony_ci		seq_printf(m, "(none)");
588c2ecf20Sopenharmony_ci	/* Print kdev. */
598c2ecf20Sopenharmony_ci	if (block->gdp)
608c2ecf20Sopenharmony_ci		seq_printf(m, " at (%3d:%6d)",
618c2ecf20Sopenharmony_ci			   MAJOR(disk_devt(block->gdp)),
628c2ecf20Sopenharmony_ci			   MINOR(disk_devt(block->gdp)));
638c2ecf20Sopenharmony_ci	else
648c2ecf20Sopenharmony_ci		seq_printf(m, "  at (???:??????)");
658c2ecf20Sopenharmony_ci	/* Print device name. */
668c2ecf20Sopenharmony_ci	if (block->gdp)
678c2ecf20Sopenharmony_ci		seq_printf(m, " is %-8s", block->gdp->disk_name);
688c2ecf20Sopenharmony_ci	else
698c2ecf20Sopenharmony_ci		seq_printf(m, " is ????????");
708c2ecf20Sopenharmony_ci	/* Print devices features. */
718c2ecf20Sopenharmony_ci	substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
728c2ecf20Sopenharmony_ci	seq_printf(m, "%4s: ", substr);
738c2ecf20Sopenharmony_ci	/* Print device status information. */
748c2ecf20Sopenharmony_ci	switch (device->state) {
758c2ecf20Sopenharmony_ci	case DASD_STATE_NEW:
768c2ecf20Sopenharmony_ci		seq_printf(m, "new");
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci	case DASD_STATE_KNOWN:
798c2ecf20Sopenharmony_ci		seq_printf(m, "detected");
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	case DASD_STATE_BASIC:
828c2ecf20Sopenharmony_ci		seq_printf(m, "basic");
838c2ecf20Sopenharmony_ci		break;
848c2ecf20Sopenharmony_ci	case DASD_STATE_UNFMT:
858c2ecf20Sopenharmony_ci		seq_printf(m, "unformatted");
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci	case DASD_STATE_READY:
888c2ecf20Sopenharmony_ci	case DASD_STATE_ONLINE:
898c2ecf20Sopenharmony_ci		seq_printf(m, "active ");
908c2ecf20Sopenharmony_ci		if (dasd_check_blocksize(block->bp_block))
918c2ecf20Sopenharmony_ci			seq_printf(m, "n/f	 ");
928c2ecf20Sopenharmony_ci		else
938c2ecf20Sopenharmony_ci			seq_printf(m,
948c2ecf20Sopenharmony_ci				   "at blocksize: %u, %lu blocks, %lu MB",
958c2ecf20Sopenharmony_ci				   block->bp_block, block->blocks,
968c2ecf20Sopenharmony_ci				   ((block->bp_block >> 9) *
978c2ecf20Sopenharmony_ci				    block->blocks) >> 11);
988c2ecf20Sopenharmony_ci		break;
998c2ecf20Sopenharmony_ci	default:
1008c2ecf20Sopenharmony_ci		seq_printf(m, "no stat");
1018c2ecf20Sopenharmony_ci		break;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	dasd_put_device(device);
1048c2ecf20Sopenharmony_ci	if (dasd_probeonly)
1058c2ecf20Sopenharmony_ci		seq_printf(m, "(probeonly)");
1068c2ecf20Sopenharmony_ci	seq_printf(m, "\n");
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void *dasd_devices_start(struct seq_file *m, loff_t *pos)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	if (*pos >= dasd_max_devindex)
1138c2ecf20Sopenharmony_ci		return NULL;
1148c2ecf20Sopenharmony_ci	return (void *)((unsigned long) *pos + 1);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void *dasd_devices_next(struct seq_file *m, void *v, loff_t *pos)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	++*pos;
1208c2ecf20Sopenharmony_ci	return dasd_devices_start(m, pos);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic void dasd_devices_stop(struct seq_file *m, void *v)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic const struct seq_operations dasd_devices_seq_ops = {
1288c2ecf20Sopenharmony_ci	.start		= dasd_devices_start,
1298c2ecf20Sopenharmony_ci	.next		= dasd_devices_next,
1308c2ecf20Sopenharmony_ci	.stop		= dasd_devices_stop,
1318c2ecf20Sopenharmony_ci	.show		= dasd_devices_show,
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#ifdef CONFIG_DASD_PROFILE
1358c2ecf20Sopenharmony_cistatic int dasd_stats_all_block_on(void)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	int i, rc;
1388c2ecf20Sopenharmony_ci	struct dasd_device *device;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	rc = 0;
1418c2ecf20Sopenharmony_ci	for (i = 0; i < dasd_max_devindex; ++i) {
1428c2ecf20Sopenharmony_ci		device = dasd_device_from_devindex(i);
1438c2ecf20Sopenharmony_ci		if (IS_ERR(device))
1448c2ecf20Sopenharmony_ci			continue;
1458c2ecf20Sopenharmony_ci		if (device->block)
1468c2ecf20Sopenharmony_ci			rc = dasd_profile_on(&device->block->profile);
1478c2ecf20Sopenharmony_ci		dasd_put_device(device);
1488c2ecf20Sopenharmony_ci		if (rc)
1498c2ecf20Sopenharmony_ci			return rc;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic void dasd_stats_all_block_off(void)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	int i;
1578c2ecf20Sopenharmony_ci	struct dasd_device *device;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	for (i = 0; i < dasd_max_devindex; ++i) {
1608c2ecf20Sopenharmony_ci		device = dasd_device_from_devindex(i);
1618c2ecf20Sopenharmony_ci		if (IS_ERR(device))
1628c2ecf20Sopenharmony_ci			continue;
1638c2ecf20Sopenharmony_ci		if (device->block)
1648c2ecf20Sopenharmony_ci			dasd_profile_off(&device->block->profile);
1658c2ecf20Sopenharmony_ci		dasd_put_device(device);
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic void dasd_stats_all_block_reset(void)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	int i;
1728c2ecf20Sopenharmony_ci	struct dasd_device *device;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	for (i = 0; i < dasd_max_devindex; ++i) {
1758c2ecf20Sopenharmony_ci		device = dasd_device_from_devindex(i);
1768c2ecf20Sopenharmony_ci		if (IS_ERR(device))
1778c2ecf20Sopenharmony_ci			continue;
1788c2ecf20Sopenharmony_ci		if (device->block)
1798c2ecf20Sopenharmony_ci			dasd_profile_reset(&device->block->profile);
1808c2ecf20Sopenharmony_ci		dasd_put_device(device);
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	int i;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	for (i = 0; i < 32; i++) {
1898c2ecf20Sopenharmony_ci		seq_printf(m, "%7d ", array[i] / factor);
1908c2ecf20Sopenharmony_ci		if (i == 15)
1918c2ecf20Sopenharmony_ci			seq_putc(m, '\n');
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci#endif /* CONFIG_DASD_PROFILE */
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int dasd_stats_proc_show(struct seq_file *m, void *v)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci#ifdef CONFIG_DASD_PROFILE
2008c2ecf20Sopenharmony_ci	struct dasd_profile_info *prof;
2018c2ecf20Sopenharmony_ci	int factor;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	spin_lock_bh(&dasd_global_profile.lock);
2048c2ecf20Sopenharmony_ci	prof = dasd_global_profile.data;
2058c2ecf20Sopenharmony_ci	if (!prof) {
2068c2ecf20Sopenharmony_ci		spin_unlock_bh(&dasd_global_profile.lock);
2078c2ecf20Sopenharmony_ci		seq_printf(m, "Statistics are off - they might be "
2088c2ecf20Sopenharmony_ci				    "switched on using 'echo set on > "
2098c2ecf20Sopenharmony_ci				    "/proc/dasd/statistics'\n");
2108c2ecf20Sopenharmony_ci		return 0;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* prevent counter 'overflow' on output */
2148c2ecf20Sopenharmony_ci	for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
2158c2ecf20Sopenharmony_ci	     factor *= 10);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	seq_printf(m, "%d dasd I/O requests\n", prof->dasd_io_reqs);
2188c2ecf20Sopenharmony_ci	seq_printf(m, "with %u sectors(512B each)\n",
2198c2ecf20Sopenharmony_ci		       prof->dasd_io_sects);
2208c2ecf20Sopenharmony_ci	seq_printf(m, "Scale Factor is  %d\n", factor);
2218c2ecf20Sopenharmony_ci	seq_printf(m,
2228c2ecf20Sopenharmony_ci		       "   __<4	   ___8	   __16	   __32	   __64	   _128	"
2238c2ecf20Sopenharmony_ci		       "   _256	   _512	   __1k	   __2k	   __4k	   __8k	"
2248c2ecf20Sopenharmony_ci		       "   _16k	   _32k	   _64k	   128k\n");
2258c2ecf20Sopenharmony_ci	seq_printf(m,
2268c2ecf20Sopenharmony_ci		       "   _256	   _512	   __1M	   __2M	   __4M	   __8M	"
2278c2ecf20Sopenharmony_ci		       "   _16M	   _32M	   _64M	   128M	   256M	   512M	"
2288c2ecf20Sopenharmony_ci		       "   __1G	   __2G	   __4G " "   _>4G\n");
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of sizes (512B secs)\n");
2318c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_secs, factor);
2328c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of I/O times (microseconds)\n");
2338c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_times, factor);
2348c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of I/O times per sector\n");
2358c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_timps, factor);
2368c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of I/O time till ssch\n");
2378c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_time1, factor);
2388c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of I/O time between ssch and irq\n");
2398c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_time2, factor);
2408c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of I/O time between ssch "
2418c2ecf20Sopenharmony_ci			    "and irq per sector\n");
2428c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_time2ps, factor);
2438c2ecf20Sopenharmony_ci	seq_printf(m, "Histogram of I/O time between irq and end\n");
2448c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_time3, factor);
2458c2ecf20Sopenharmony_ci	seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
2468c2ecf20Sopenharmony_ci	dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
2478c2ecf20Sopenharmony_ci	spin_unlock_bh(&dasd_global_profile.lock);
2488c2ecf20Sopenharmony_ci#else
2498c2ecf20Sopenharmony_ci	seq_printf(m, "Statistics are not activated in this kernel\n");
2508c2ecf20Sopenharmony_ci#endif
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int dasd_stats_proc_open(struct inode *inode, struct file *file)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	return single_open(file, dasd_stats_proc_show, NULL);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic ssize_t dasd_stats_proc_write(struct file *file,
2608c2ecf20Sopenharmony_ci		const char __user *user_buf, size_t user_len, loff_t *pos)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci#ifdef CONFIG_DASD_PROFILE
2638c2ecf20Sopenharmony_ci	char *buffer, *str;
2648c2ecf20Sopenharmony_ci	int rc;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (user_len > 65536)
2678c2ecf20Sopenharmony_ci		user_len = 65536;
2688c2ecf20Sopenharmony_ci	buffer = dasd_get_user_string(user_buf, user_len);
2698c2ecf20Sopenharmony_ci	if (IS_ERR(buffer))
2708c2ecf20Sopenharmony_ci		return PTR_ERR(buffer);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* check for valid verbs */
2738c2ecf20Sopenharmony_ci	str = skip_spaces(buffer);
2748c2ecf20Sopenharmony_ci	if (strncmp(str, "set", 3) == 0 && isspace(str[3])) {
2758c2ecf20Sopenharmony_ci		/* 'set xxx' was given */
2768c2ecf20Sopenharmony_ci		str = skip_spaces(str + 4);
2778c2ecf20Sopenharmony_ci		if (strcmp(str, "on") == 0) {
2788c2ecf20Sopenharmony_ci			/* switch on statistics profiling */
2798c2ecf20Sopenharmony_ci			rc = dasd_stats_all_block_on();
2808c2ecf20Sopenharmony_ci			if (rc) {
2818c2ecf20Sopenharmony_ci				dasd_stats_all_block_off();
2828c2ecf20Sopenharmony_ci				goto out_error;
2838c2ecf20Sopenharmony_ci			}
2848c2ecf20Sopenharmony_ci			rc = dasd_profile_on(&dasd_global_profile);
2858c2ecf20Sopenharmony_ci			if (rc) {
2868c2ecf20Sopenharmony_ci				dasd_stats_all_block_off();
2878c2ecf20Sopenharmony_ci				goto out_error;
2888c2ecf20Sopenharmony_ci			}
2898c2ecf20Sopenharmony_ci			dasd_profile_reset(&dasd_global_profile);
2908c2ecf20Sopenharmony_ci			dasd_global_profile_level = DASD_PROFILE_ON;
2918c2ecf20Sopenharmony_ci			pr_info("The statistics feature has been switched "
2928c2ecf20Sopenharmony_ci				"on\n");
2938c2ecf20Sopenharmony_ci		} else if (strcmp(str, "off") == 0) {
2948c2ecf20Sopenharmony_ci			/* switch off statistics profiling */
2958c2ecf20Sopenharmony_ci			dasd_global_profile_level = DASD_PROFILE_OFF;
2968c2ecf20Sopenharmony_ci			dasd_profile_off(&dasd_global_profile);
2978c2ecf20Sopenharmony_ci			dasd_stats_all_block_off();
2988c2ecf20Sopenharmony_ci			pr_info("The statistics feature has been switched "
2998c2ecf20Sopenharmony_ci				"off\n");
3008c2ecf20Sopenharmony_ci		} else
3018c2ecf20Sopenharmony_ci			goto out_parse_error;
3028c2ecf20Sopenharmony_ci	} else if (strncmp(str, "reset", 5) == 0) {
3038c2ecf20Sopenharmony_ci		/* reset the statistics */
3048c2ecf20Sopenharmony_ci		dasd_profile_reset(&dasd_global_profile);
3058c2ecf20Sopenharmony_ci		dasd_stats_all_block_reset();
3068c2ecf20Sopenharmony_ci		pr_info("The statistics have been reset\n");
3078c2ecf20Sopenharmony_ci	} else
3088c2ecf20Sopenharmony_ci		goto out_parse_error;
3098c2ecf20Sopenharmony_ci	vfree(buffer);
3108c2ecf20Sopenharmony_ci	return user_len;
3118c2ecf20Sopenharmony_ciout_parse_error:
3128c2ecf20Sopenharmony_ci	rc = -EINVAL;
3138c2ecf20Sopenharmony_ci	pr_warn("%s is not a supported value for /proc/dasd/statistics\n", str);
3148c2ecf20Sopenharmony_ciout_error:
3158c2ecf20Sopenharmony_ci	vfree(buffer);
3168c2ecf20Sopenharmony_ci	return rc;
3178c2ecf20Sopenharmony_ci#else
3188c2ecf20Sopenharmony_ci	pr_warn("/proc/dasd/statistics: is not activated in this kernel\n");
3198c2ecf20Sopenharmony_ci	return user_len;
3208c2ecf20Sopenharmony_ci#endif				/* CONFIG_DASD_PROFILE */
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic const struct proc_ops dasd_stats_proc_ops = {
3248c2ecf20Sopenharmony_ci	.proc_open	= dasd_stats_proc_open,
3258c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
3268c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
3278c2ecf20Sopenharmony_ci	.proc_release	= single_release,
3288c2ecf20Sopenharmony_ci	.proc_write	= dasd_stats_proc_write,
3298c2ecf20Sopenharmony_ci};
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/*
3328c2ecf20Sopenharmony_ci * Create dasd proc-fs entries.
3338c2ecf20Sopenharmony_ci * In case creation failed, cleanup and return -ENOENT.
3348c2ecf20Sopenharmony_ci */
3358c2ecf20Sopenharmony_ciint
3368c2ecf20Sopenharmony_cidasd_proc_init(void)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	dasd_proc_root_entry = proc_mkdir("dasd", NULL);
3398c2ecf20Sopenharmony_ci	if (!dasd_proc_root_entry)
3408c2ecf20Sopenharmony_ci		goto out_nodasd;
3418c2ecf20Sopenharmony_ci	dasd_devices_entry = proc_create_seq("devices", 0444,
3428c2ecf20Sopenharmony_ci					 dasd_proc_root_entry,
3438c2ecf20Sopenharmony_ci					 &dasd_devices_seq_ops);
3448c2ecf20Sopenharmony_ci	if (!dasd_devices_entry)
3458c2ecf20Sopenharmony_ci		goto out_nodevices;
3468c2ecf20Sopenharmony_ci	dasd_statistics_entry = proc_create("statistics",
3478c2ecf20Sopenharmony_ci					    S_IFREG | S_IRUGO | S_IWUSR,
3488c2ecf20Sopenharmony_ci					    dasd_proc_root_entry,
3498c2ecf20Sopenharmony_ci					    &dasd_stats_proc_ops);
3508c2ecf20Sopenharmony_ci	if (!dasd_statistics_entry)
3518c2ecf20Sopenharmony_ci		goto out_nostatistics;
3528c2ecf20Sopenharmony_ci	return 0;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci out_nostatistics:
3558c2ecf20Sopenharmony_ci	remove_proc_entry("devices", dasd_proc_root_entry);
3568c2ecf20Sopenharmony_ci out_nodevices:
3578c2ecf20Sopenharmony_ci	remove_proc_entry("dasd", NULL);
3588c2ecf20Sopenharmony_ci out_nodasd:
3598c2ecf20Sopenharmony_ci	return -ENOENT;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_civoid
3638c2ecf20Sopenharmony_cidasd_proc_exit(void)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	remove_proc_entry("devices", dasd_proc_root_entry);
3668c2ecf20Sopenharmony_ci	remove_proc_entry("statistics", dasd_proc_root_entry);
3678c2ecf20Sopenharmony_ci	remove_proc_entry("dasd", NULL);
3688c2ecf20Sopenharmony_ci}
369