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, 2001 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * i/o controls for the dasd driver. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "dasd" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/compat.h> 178c2ecf20Sopenharmony_ci#include <linux/major.h> 188c2ecf20Sopenharmony_ci#include <linux/fs.h> 198c2ecf20Sopenharmony_ci#include <linux/blkpg.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <asm/ccwdev.h> 228c2ecf20Sopenharmony_ci#include <asm/schid.h> 238c2ecf20Sopenharmony_ci#include <asm/cmb.h> 248c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 258c2ecf20Sopenharmony_ci#include <linux/dasd_mod.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* This is ugly... */ 288c2ecf20Sopenharmony_ci#define PRINTK_HEADER "dasd_ioctl:" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "dasd_int.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int 348c2ecf20Sopenharmony_cidasd_ioctl_api_version(void __user *argp) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int ver = DASD_API_VERSION; 378c2ecf20Sopenharmony_ci return put_user(ver, (int __user *)argp); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * Enable device. 428c2ecf20Sopenharmony_ci * used by dasdfmt after BIODASDDISABLE to retrigger blocksize detection 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cistatic int 458c2ecf20Sopenharmony_cidasd_ioctl_enable(struct block_device *bdev) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct dasd_device *base; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 508c2ecf20Sopenharmony_ci return -EACCES; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 538c2ecf20Sopenharmony_ci if (!base) 548c2ecf20Sopenharmony_ci return -ENODEV; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci dasd_enable_device(base); 578c2ecf20Sopenharmony_ci /* Formatting the dasd device can change the capacity. */ 588c2ecf20Sopenharmony_ci bd_set_nr_sectors(bdev, get_capacity(base->block->gdp)); 598c2ecf20Sopenharmony_ci dasd_put_device(base); 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * Disable device. 658c2ecf20Sopenharmony_ci * Used by dasdfmt. Disable I/O operations but allow ioctls. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic int 688c2ecf20Sopenharmony_cidasd_ioctl_disable(struct block_device *bdev) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct dasd_device *base; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 738c2ecf20Sopenharmony_ci return -EACCES; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 768c2ecf20Sopenharmony_ci if (!base) 778c2ecf20Sopenharmony_ci return -ENODEV; 788c2ecf20Sopenharmony_ci /* 798c2ecf20Sopenharmony_ci * Man this is sick. We don't do a real disable but only downgrade 808c2ecf20Sopenharmony_ci * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses 818c2ecf20Sopenharmony_ci * BIODASDDISABLE to disable accesses to the device via the block 828c2ecf20Sopenharmony_ci * device layer but it still wants to do i/o on the device by 838c2ecf20Sopenharmony_ci * using the BIODASDFMT ioctl. Therefore the correct state for the 848c2ecf20Sopenharmony_ci * device is DASD_STATE_BASIC that allows to do basic i/o. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci dasd_set_target_state(base, DASD_STATE_BASIC); 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * Set i_size to zero, since read, write, etc. check against this 898c2ecf20Sopenharmony_ci * value. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci bd_set_nr_sectors(bdev, 0); 928c2ecf20Sopenharmony_ci dasd_put_device(base); 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Quiesce device. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistatic int dasd_ioctl_quiesce(struct dasd_block *block) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci unsigned long flags; 1028c2ecf20Sopenharmony_ci struct dasd_device *base; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci base = block->base; 1058c2ecf20Sopenharmony_ci if (!capable (CAP_SYS_ADMIN)) 1068c2ecf20Sopenharmony_ci return -EACCES; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci pr_info("%s: The DASD has been put in the quiesce " 1098c2ecf20Sopenharmony_ci "state\n", dev_name(&base->cdev->dev)); 1108c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); 1118c2ecf20Sopenharmony_ci dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE); 1128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* 1188c2ecf20Sopenharmony_ci * Resume device. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistatic int dasd_ioctl_resume(struct dasd_block *block) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned long flags; 1238c2ecf20Sopenharmony_ci struct dasd_device *base; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci base = block->base; 1268c2ecf20Sopenharmony_ci if (!capable (CAP_SYS_ADMIN)) 1278c2ecf20Sopenharmony_ci return -EACCES; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci pr_info("%s: I/O operations have been resumed " 1308c2ecf20Sopenharmony_ci "on the DASD\n", dev_name(&base->cdev->dev)); 1318c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); 1328c2ecf20Sopenharmony_ci dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE); 1338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci dasd_schedule_block_bh(block); 1368c2ecf20Sopenharmony_ci dasd_schedule_device_bh(base); 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * Abort all failfast I/O on a device. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic int dasd_ioctl_abortio(struct dasd_block *block) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci unsigned long flags; 1468c2ecf20Sopenharmony_ci struct dasd_device *base; 1478c2ecf20Sopenharmony_ci struct dasd_ccw_req *cqr, *n; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci base = block->base; 1508c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 1518c2ecf20Sopenharmony_ci return -EACCES; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (test_and_set_bit(DASD_FLAG_ABORTALL, &base->flags)) 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag set"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci spin_lock_irqsave(&block->request_queue_lock, flags); 1588c2ecf20Sopenharmony_ci spin_lock(&block->queue_lock); 1598c2ecf20Sopenharmony_ci list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) { 1608c2ecf20Sopenharmony_ci if (test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && 1618c2ecf20Sopenharmony_ci cqr->callback_data && 1628c2ecf20Sopenharmony_ci cqr->callback_data != DASD_SLEEPON_START_TAG && 1638c2ecf20Sopenharmony_ci cqr->callback_data != DASD_SLEEPON_END_TAG) { 1648c2ecf20Sopenharmony_ci spin_unlock(&block->queue_lock); 1658c2ecf20Sopenharmony_ci blk_abort_request(cqr->callback_data); 1668c2ecf20Sopenharmony_ci spin_lock(&block->queue_lock); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci spin_unlock(&block->queue_lock); 1708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&block->request_queue_lock, flags); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci dasd_schedule_block_bh(block); 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * Allow I/O on a device 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic int dasd_ioctl_allowio(struct dasd_block *block) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct dasd_device *base; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci base = block->base; 1848c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 1858c2ecf20Sopenharmony_ci return -EACCES; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (test_and_clear_bit(DASD_FLAG_ABORTALL, &base->flags)) 1888c2ecf20Sopenharmony_ci DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag unset"); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* 1948c2ecf20Sopenharmony_ci * performs formatting of _device_ according to _fdata_ 1958c2ecf20Sopenharmony_ci * Note: The discipline's format_function is assumed to deliver formatting 1968c2ecf20Sopenharmony_ci * commands to format multiple units of the device. In terms of the ECKD 1978c2ecf20Sopenharmony_ci * devices this means CCWs are generated to format multiple tracks. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic int 2008c2ecf20Sopenharmony_cidasd_format(struct dasd_block *block, struct format_data_t *fdata) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct dasd_device *base; 2038c2ecf20Sopenharmony_ci int rc; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci base = block->base; 2068c2ecf20Sopenharmony_ci if (base->discipline->format_device == NULL) 2078c2ecf20Sopenharmony_ci return -EPERM; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (base->state != DASD_STATE_BASIC) { 2108c2ecf20Sopenharmony_ci pr_warn("%s: The DASD cannot be formatted while it is enabled\n", 2118c2ecf20Sopenharmony_ci dev_name(&base->cdev->dev)); 2128c2ecf20Sopenharmony_ci return -EBUSY; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci DBF_DEV_EVENT(DBF_NOTICE, base, 2168c2ecf20Sopenharmony_ci "formatting units %u to %u (%u B blocks) flags %u", 2178c2ecf20Sopenharmony_ci fdata->start_unit, 2188c2ecf20Sopenharmony_ci fdata->stop_unit, fdata->blksize, fdata->intensity); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Since dasdfmt keeps the device open after it was disabled, 2218c2ecf20Sopenharmony_ci * there still exists an inode for this device. 2228c2ecf20Sopenharmony_ci * We must update i_blkbits, otherwise we might get errors when 2238c2ecf20Sopenharmony_ci * enabling the device later. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci if (fdata->start_unit == 0) { 2268c2ecf20Sopenharmony_ci struct block_device *bdev = bdget_disk(block->gdp, 0); 2278c2ecf20Sopenharmony_ci bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize); 2288c2ecf20Sopenharmony_ci bdput(bdev); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci rc = base->discipline->format_device(base, fdata, 1); 2328c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 2338c2ecf20Sopenharmony_ci rc = base->discipline->format_device(base, fdata, 0); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return rc; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int dasd_check_format(struct dasd_block *block, 2398c2ecf20Sopenharmony_ci struct format_check_t *cdata) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct dasd_device *base; 2428c2ecf20Sopenharmony_ci int rc; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci base = block->base; 2458c2ecf20Sopenharmony_ci if (!base->discipline->check_device_format) 2468c2ecf20Sopenharmony_ci return -ENOTTY; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci rc = base->discipline->check_device_format(base, cdata, 1); 2498c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 2508c2ecf20Sopenharmony_ci rc = base->discipline->check_device_format(base, cdata, 0); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return rc; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * Format device. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_cistatic int 2598c2ecf20Sopenharmony_cidasd_ioctl_format(struct block_device *bdev, void __user *argp) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct dasd_device *base; 2628c2ecf20Sopenharmony_ci struct format_data_t fdata; 2638c2ecf20Sopenharmony_ci int rc; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 2668c2ecf20Sopenharmony_ci return -EACCES; 2678c2ecf20Sopenharmony_ci if (!argp) 2688c2ecf20Sopenharmony_ci return -EINVAL; 2698c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 2708c2ecf20Sopenharmony_ci if (!base) 2718c2ecf20Sopenharmony_ci return -ENODEV; 2728c2ecf20Sopenharmony_ci if (base->features & DASD_FEATURE_READONLY || 2738c2ecf20Sopenharmony_ci test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { 2748c2ecf20Sopenharmony_ci dasd_put_device(base); 2758c2ecf20Sopenharmony_ci return -EROFS; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { 2788c2ecf20Sopenharmony_ci dasd_put_device(base); 2798c2ecf20Sopenharmony_ci return -EFAULT; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci if (bdev_is_partition(bdev)) { 2828c2ecf20Sopenharmony_ci pr_warn("%s: The specified DASD is a partition and cannot be formatted\n", 2838c2ecf20Sopenharmony_ci dev_name(&base->cdev->dev)); 2848c2ecf20Sopenharmony_ci dasd_put_device(base); 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci rc = dasd_format(base->block, &fdata); 2888c2ecf20Sopenharmony_ci dasd_put_device(base); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return rc; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * Check device format 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_cistatic int dasd_ioctl_check_format(struct block_device *bdev, void __user *argp) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct format_check_t cdata; 2998c2ecf20Sopenharmony_ci struct dasd_device *base; 3008c2ecf20Sopenharmony_ci int rc = 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!argp) 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 3068c2ecf20Sopenharmony_ci if (!base) 3078c2ecf20Sopenharmony_ci return -ENODEV; 3088c2ecf20Sopenharmony_ci if (bdev_is_partition(bdev)) { 3098c2ecf20Sopenharmony_ci pr_warn("%s: The specified DASD is a partition and cannot be checked\n", 3108c2ecf20Sopenharmony_ci dev_name(&base->cdev->dev)); 3118c2ecf20Sopenharmony_ci rc = -EINVAL; 3128c2ecf20Sopenharmony_ci goto out_err; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (copy_from_user(&cdata, argp, sizeof(cdata))) { 3168c2ecf20Sopenharmony_ci rc = -EFAULT; 3178c2ecf20Sopenharmony_ci goto out_err; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci rc = dasd_check_format(base->block, &cdata); 3218c2ecf20Sopenharmony_ci if (rc) 3228c2ecf20Sopenharmony_ci goto out_err; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (copy_to_user(argp, &cdata, sizeof(cdata))) 3258c2ecf20Sopenharmony_ci rc = -EFAULT; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciout_err: 3288c2ecf20Sopenharmony_ci dasd_put_device(base); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return rc; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int dasd_release_space(struct dasd_device *device, 3348c2ecf20Sopenharmony_ci struct format_data_t *rdata) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci if (!device->discipline->is_ese && !device->discipline->is_ese(device)) 3378c2ecf20Sopenharmony_ci return -ENOTSUPP; 3388c2ecf20Sopenharmony_ci if (!device->discipline->release_space) 3398c2ecf20Sopenharmony_ci return -ENOTSUPP; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return device->discipline->release_space(device, rdata); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* 3458c2ecf20Sopenharmony_ci * Release allocated space 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_cistatic int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct format_data_t rdata; 3508c2ecf20Sopenharmony_ci struct dasd_device *base; 3518c2ecf20Sopenharmony_ci int rc = 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 3548c2ecf20Sopenharmony_ci return -EACCES; 3558c2ecf20Sopenharmony_ci if (!argp) 3568c2ecf20Sopenharmony_ci return -EINVAL; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 3598c2ecf20Sopenharmony_ci if (!base) 3608c2ecf20Sopenharmony_ci return -ENODEV; 3618c2ecf20Sopenharmony_ci if (base->features & DASD_FEATURE_READONLY || 3628c2ecf20Sopenharmony_ci test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { 3638c2ecf20Sopenharmony_ci rc = -EROFS; 3648c2ecf20Sopenharmony_ci goto out_err; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci if (bdev_is_partition(bdev)) { 3678c2ecf20Sopenharmony_ci pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n", 3688c2ecf20Sopenharmony_ci dev_name(&base->cdev->dev)); 3698c2ecf20Sopenharmony_ci rc = -EINVAL; 3708c2ecf20Sopenharmony_ci goto out_err; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (copy_from_user(&rdata, argp, sizeof(rdata))) { 3748c2ecf20Sopenharmony_ci rc = -EFAULT; 3758c2ecf20Sopenharmony_ci goto out_err; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci rc = dasd_release_space(base, &rdata); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ciout_err: 3818c2ecf20Sopenharmony_ci dasd_put_device(base); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return rc; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci#ifdef CONFIG_DASD_PROFILE 3878c2ecf20Sopenharmony_ci/* 3888c2ecf20Sopenharmony_ci * Reset device profile information 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_cistatic int dasd_ioctl_reset_profile(struct dasd_block *block) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci dasd_profile_reset(&block->profile); 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* 3978c2ecf20Sopenharmony_ci * Return device profile information 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_cistatic int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct dasd_profile_info_t *data; 4028c2ecf20Sopenharmony_ci int rc = 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci data = kmalloc(sizeof(*data), GFP_KERNEL); 4058c2ecf20Sopenharmony_ci if (!data) 4068c2ecf20Sopenharmony_ci return -ENOMEM; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci spin_lock_bh(&block->profile.lock); 4098c2ecf20Sopenharmony_ci if (block->profile.data) { 4108c2ecf20Sopenharmony_ci data->dasd_io_reqs = block->profile.data->dasd_io_reqs; 4118c2ecf20Sopenharmony_ci data->dasd_io_sects = block->profile.data->dasd_io_sects; 4128c2ecf20Sopenharmony_ci memcpy(data->dasd_io_secs, block->profile.data->dasd_io_secs, 4138c2ecf20Sopenharmony_ci sizeof(data->dasd_io_secs)); 4148c2ecf20Sopenharmony_ci memcpy(data->dasd_io_times, block->profile.data->dasd_io_times, 4158c2ecf20Sopenharmony_ci sizeof(data->dasd_io_times)); 4168c2ecf20Sopenharmony_ci memcpy(data->dasd_io_timps, block->profile.data->dasd_io_timps, 4178c2ecf20Sopenharmony_ci sizeof(data->dasd_io_timps)); 4188c2ecf20Sopenharmony_ci memcpy(data->dasd_io_time1, block->profile.data->dasd_io_time1, 4198c2ecf20Sopenharmony_ci sizeof(data->dasd_io_time1)); 4208c2ecf20Sopenharmony_ci memcpy(data->dasd_io_time2, block->profile.data->dasd_io_time2, 4218c2ecf20Sopenharmony_ci sizeof(data->dasd_io_time2)); 4228c2ecf20Sopenharmony_ci memcpy(data->dasd_io_time2ps, 4238c2ecf20Sopenharmony_ci block->profile.data->dasd_io_time2ps, 4248c2ecf20Sopenharmony_ci sizeof(data->dasd_io_time2ps)); 4258c2ecf20Sopenharmony_ci memcpy(data->dasd_io_time3, block->profile.data->dasd_io_time3, 4268c2ecf20Sopenharmony_ci sizeof(data->dasd_io_time3)); 4278c2ecf20Sopenharmony_ci memcpy(data->dasd_io_nr_req, 4288c2ecf20Sopenharmony_ci block->profile.data->dasd_io_nr_req, 4298c2ecf20Sopenharmony_ci sizeof(data->dasd_io_nr_req)); 4308c2ecf20Sopenharmony_ci spin_unlock_bh(&block->profile.lock); 4318c2ecf20Sopenharmony_ci } else { 4328c2ecf20Sopenharmony_ci spin_unlock_bh(&block->profile.lock); 4338c2ecf20Sopenharmony_ci rc = -EIO; 4348c2ecf20Sopenharmony_ci goto out; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci if (copy_to_user(argp, data, sizeof(*data))) 4378c2ecf20Sopenharmony_ci rc = -EFAULT; 4388c2ecf20Sopenharmony_ciout: 4398c2ecf20Sopenharmony_ci kfree(data); 4408c2ecf20Sopenharmony_ci return rc; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci#else 4438c2ecf20Sopenharmony_cistatic int dasd_ioctl_reset_profile(struct dasd_block *block) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci return -ENOTTY; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci return -ENOTTY; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci#endif 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* 4558c2ecf20Sopenharmony_ci * Return dasd information. Used for BIODASDINFO and BIODASDINFO2. 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_cistatic int __dasd_ioctl_information(struct dasd_block *block, 4588c2ecf20Sopenharmony_ci struct dasd_information2_t *dasd_info) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct subchannel_id sch_id; 4618c2ecf20Sopenharmony_ci struct ccw_dev_id dev_id; 4628c2ecf20Sopenharmony_ci struct dasd_device *base; 4638c2ecf20Sopenharmony_ci struct ccw_device *cdev; 4648c2ecf20Sopenharmony_ci struct list_head *l; 4658c2ecf20Sopenharmony_ci unsigned long flags; 4668c2ecf20Sopenharmony_ci int rc; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci base = block->base; 4698c2ecf20Sopenharmony_ci if (!base->discipline || !base->discipline->fill_info) 4708c2ecf20Sopenharmony_ci return -EINVAL; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci rc = base->discipline->fill_info(base, dasd_info); 4738c2ecf20Sopenharmony_ci if (rc) 4748c2ecf20Sopenharmony_ci return rc; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci cdev = base->cdev; 4778c2ecf20Sopenharmony_ci ccw_device_get_id(cdev, &dev_id); 4788c2ecf20Sopenharmony_ci ccw_device_get_schid(cdev, &sch_id); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci dasd_info->devno = dev_id.devno; 4818c2ecf20Sopenharmony_ci dasd_info->schid = sch_id.sch_no; 4828c2ecf20Sopenharmony_ci dasd_info->cu_type = cdev->id.cu_type; 4838c2ecf20Sopenharmony_ci dasd_info->cu_model = cdev->id.cu_model; 4848c2ecf20Sopenharmony_ci dasd_info->dev_type = cdev->id.dev_type; 4858c2ecf20Sopenharmony_ci dasd_info->dev_model = cdev->id.dev_model; 4868c2ecf20Sopenharmony_ci dasd_info->status = base->state; 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * The open_count is increased for every opener, that includes 4898c2ecf20Sopenharmony_ci * the blkdev_get in dasd_scan_partitions. 4908c2ecf20Sopenharmony_ci * This must be hidden from user-space. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci dasd_info->open_count = atomic_read(&block->open_count); 4938c2ecf20Sopenharmony_ci if (!block->bdev) 4948c2ecf20Sopenharmony_ci dasd_info->open_count++; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * check if device is really formatted 4988c2ecf20Sopenharmony_ci * LDL / CDL was returned by 'fill_info' 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci if ((base->state < DASD_STATE_READY) || 5018c2ecf20Sopenharmony_ci (dasd_check_blocksize(block->bp_block))) 5028c2ecf20Sopenharmony_ci dasd_info->format = DASD_FORMAT_NONE; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci dasd_info->features |= 5058c2ecf20Sopenharmony_ci ((base->features & DASD_FEATURE_READONLY) != 0); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci memcpy(dasd_info->type, base->discipline->name, 4); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); 5108c2ecf20Sopenharmony_ci list_for_each(l, &base->ccw_queue) 5118c2ecf20Sopenharmony_ci dasd_info->chanq_len++; 5128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int dasd_ioctl_information(struct dasd_block *block, void __user *argp, 5178c2ecf20Sopenharmony_ci size_t copy_size) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct dasd_information2_t *dasd_info; 5208c2ecf20Sopenharmony_ci int error; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci dasd_info = kzalloc(sizeof(*dasd_info), GFP_KERNEL); 5238c2ecf20Sopenharmony_ci if (!dasd_info) 5248c2ecf20Sopenharmony_ci return -ENOMEM; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci error = __dasd_ioctl_information(block, dasd_info); 5278c2ecf20Sopenharmony_ci if (!error && copy_to_user(argp, dasd_info, copy_size)) 5288c2ecf20Sopenharmony_ci error = -EFAULT; 5298c2ecf20Sopenharmony_ci kfree(dasd_info); 5308c2ecf20Sopenharmony_ci return error; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* 5348c2ecf20Sopenharmony_ci * Set read only 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_cistatic int 5378c2ecf20Sopenharmony_cidasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct dasd_device *base; 5408c2ecf20Sopenharmony_ci int intval, rc; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 5438c2ecf20Sopenharmony_ci return -EACCES; 5448c2ecf20Sopenharmony_ci if (bdev_is_partition(bdev)) 5458c2ecf20Sopenharmony_ci // ro setting is not allowed for partitions 5468c2ecf20Sopenharmony_ci return -EINVAL; 5478c2ecf20Sopenharmony_ci if (get_user(intval, (int __user *)argp)) 5488c2ecf20Sopenharmony_ci return -EFAULT; 5498c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 5508c2ecf20Sopenharmony_ci if (!base) 5518c2ecf20Sopenharmony_ci return -ENODEV; 5528c2ecf20Sopenharmony_ci if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { 5538c2ecf20Sopenharmony_ci dasd_put_device(base); 5548c2ecf20Sopenharmony_ci return -EROFS; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci set_disk_ro(bdev->bd_disk, intval); 5578c2ecf20Sopenharmony_ci rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); 5588c2ecf20Sopenharmony_ci dasd_put_device(base); 5598c2ecf20Sopenharmony_ci return rc; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, 5638c2ecf20Sopenharmony_ci struct cmbdata __user *argp) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci size_t size = _IOC_SIZE(cmd); 5668c2ecf20Sopenharmony_ci struct cmbdata data; 5678c2ecf20Sopenharmony_ci int ret; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci ret = cmf_readall(block->base->cdev, &data); 5708c2ecf20Sopenharmony_ci if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp)))) 5718c2ecf20Sopenharmony_ci return -EFAULT; 5728c2ecf20Sopenharmony_ci return ret; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ciint dasd_ioctl(struct block_device *bdev, fmode_t mode, 5768c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct dasd_block *block; 5798c2ecf20Sopenharmony_ci struct dasd_device *base; 5808c2ecf20Sopenharmony_ci void __user *argp; 5818c2ecf20Sopenharmony_ci int rc; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (is_compat_task()) 5848c2ecf20Sopenharmony_ci argp = compat_ptr(arg); 5858c2ecf20Sopenharmony_ci else 5868c2ecf20Sopenharmony_ci argp = (void __user *)arg; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { 5898c2ecf20Sopenharmony_ci PRINT_DEBUG("empty data ptr"); 5908c2ecf20Sopenharmony_ci return -EINVAL; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(bdev->bd_disk); 5948c2ecf20Sopenharmony_ci if (!base) 5958c2ecf20Sopenharmony_ci return -ENODEV; 5968c2ecf20Sopenharmony_ci block = base->block; 5978c2ecf20Sopenharmony_ci rc = 0; 5988c2ecf20Sopenharmony_ci switch (cmd) { 5998c2ecf20Sopenharmony_ci case BIODASDDISABLE: 6008c2ecf20Sopenharmony_ci rc = dasd_ioctl_disable(bdev); 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci case BIODASDENABLE: 6038c2ecf20Sopenharmony_ci rc = dasd_ioctl_enable(bdev); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci case BIODASDQUIESCE: 6068c2ecf20Sopenharmony_ci rc = dasd_ioctl_quiesce(block); 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci case BIODASDRESUME: 6098c2ecf20Sopenharmony_ci rc = dasd_ioctl_resume(block); 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci case BIODASDABORTIO: 6128c2ecf20Sopenharmony_ci rc = dasd_ioctl_abortio(block); 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci case BIODASDALLOWIO: 6158c2ecf20Sopenharmony_ci rc = dasd_ioctl_allowio(block); 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci case BIODASDFMT: 6188c2ecf20Sopenharmony_ci rc = dasd_ioctl_format(bdev, argp); 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci case BIODASDCHECKFMT: 6218c2ecf20Sopenharmony_ci rc = dasd_ioctl_check_format(bdev, argp); 6228c2ecf20Sopenharmony_ci break; 6238c2ecf20Sopenharmony_ci case BIODASDINFO: 6248c2ecf20Sopenharmony_ci rc = dasd_ioctl_information(block, argp, 6258c2ecf20Sopenharmony_ci sizeof(struct dasd_information_t)); 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci case BIODASDINFO2: 6288c2ecf20Sopenharmony_ci rc = dasd_ioctl_information(block, argp, 6298c2ecf20Sopenharmony_ci sizeof(struct dasd_information2_t)); 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci case BIODASDPRRD: 6328c2ecf20Sopenharmony_ci rc = dasd_ioctl_read_profile(block, argp); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci case BIODASDPRRST: 6358c2ecf20Sopenharmony_ci rc = dasd_ioctl_reset_profile(block); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case BLKROSET: 6388c2ecf20Sopenharmony_ci rc = dasd_ioctl_set_ro(bdev, argp); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case DASDAPIVER: 6418c2ecf20Sopenharmony_ci rc = dasd_ioctl_api_version(argp); 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case BIODASDCMFENABLE: 6448c2ecf20Sopenharmony_ci rc = enable_cmf(base->cdev); 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci case BIODASDCMFDISABLE: 6478c2ecf20Sopenharmony_ci rc = disable_cmf(base->cdev); 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci case BIODASDREADALLCMB: 6508c2ecf20Sopenharmony_ci rc = dasd_ioctl_readall_cmb(block, cmd, argp); 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case BIODASDRAS: 6538c2ecf20Sopenharmony_ci rc = dasd_ioctl_release_space(bdev, argp); 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci default: 6568c2ecf20Sopenharmony_ci /* if the discipline has an ioctl method try it. */ 6578c2ecf20Sopenharmony_ci rc = -ENOTTY; 6588c2ecf20Sopenharmony_ci if (base->discipline->ioctl) 6598c2ecf20Sopenharmony_ci rc = base->discipline->ioctl(block, cmd, argp); 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci dasd_put_device(base); 6628c2ecf20Sopenharmony_ci return rc; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/** 6678c2ecf20Sopenharmony_ci * dasd_biodasdinfo() - fill out the dasd information structure 6688c2ecf20Sopenharmony_ci * @disk [in]: pointer to gendisk structure that references a DASD 6698c2ecf20Sopenharmony_ci * @info [out]: pointer to the dasd_information2_t structure 6708c2ecf20Sopenharmony_ci * 6718c2ecf20Sopenharmony_ci * Provide access to DASD specific information. 6728c2ecf20Sopenharmony_ci * The gendisk structure is checked if it belongs to the DASD driver by 6738c2ecf20Sopenharmony_ci * comparing the gendisk->fops pointer. 6748c2ecf20Sopenharmony_ci * If it does not belong to the DASD driver -EINVAL is returned. 6758c2ecf20Sopenharmony_ci * Otherwise the provided dasd_information2_t structure is filled out. 6768c2ecf20Sopenharmony_ci * 6778c2ecf20Sopenharmony_ci * Returns: 6788c2ecf20Sopenharmony_ci * %0 on success and a negative error value on failure. 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ciint dasd_biodasdinfo(struct gendisk *disk, struct dasd_information2_t *info) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct dasd_device *base; 6838c2ecf20Sopenharmony_ci int error; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (disk->fops != &dasd_device_operations) 6868c2ecf20Sopenharmony_ci return -EINVAL; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci base = dasd_device_from_gendisk(disk); 6898c2ecf20Sopenharmony_ci if (!base) 6908c2ecf20Sopenharmony_ci return -ENODEV; 6918c2ecf20Sopenharmony_ci error = __dasd_ioctl_information(base->block, info); 6928c2ecf20Sopenharmony_ci dasd_put_device(base); 6938c2ecf20Sopenharmony_ci return error; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci/* export that symbol_get in partition detection is possible */ 6968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dasd_biodasdinfo); 697