730 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>4 * Horst Hummel <Horst.Hummel@de.ibm.com>5 * Carsten Otte <Cotte@de.ibm.com>6 * Martin Schwidefsky <schwidefsky@de.ibm.com>7 * Bugreports.to..: <Linux390@de.ibm.com>8 * Copyright IBM Corp. 1999, 20019 *10 * i/o controls for the dasd driver.11 */12 13#include <linux/interrupt.h>14#include <linux/compat.h>15#include <linux/major.h>16#include <linux/fs.h>17#include <linux/blkpg.h>18#include <linux/slab.h>19#include <asm/ccwdev.h>20#include <asm/schid.h>21#include <asm/cmb.h>22#include <linux/uaccess.h>23#include <linux/dasd_mod.h>24 25#include "dasd_int.h"26 27static int28dasd_ioctl_api_version(void __user *argp)29{30 int ver = DASD_API_VERSION;31 return put_user(ver, (int __user *)argp);32}33 34/*35 * Enable device.36 * used by dasdfmt after BIODASDDISABLE to retrigger blocksize detection37 */38static int39dasd_ioctl_enable(struct block_device *bdev)40{41 struct dasd_device *base;42 43 if (!capable(CAP_SYS_ADMIN))44 return -EACCES;45 46 base = dasd_device_from_gendisk(bdev->bd_disk);47 if (!base)48 return -ENODEV;49 50 dasd_enable_device(base);51 dasd_put_device(base);52 return 0;53}54 55/*56 * Disable device.57 * Used by dasdfmt. Disable I/O operations but allow ioctls.58 */59static int60dasd_ioctl_disable(struct block_device *bdev)61{62 struct dasd_device *base;63 64 if (!capable(CAP_SYS_ADMIN))65 return -EACCES;66 67 base = dasd_device_from_gendisk(bdev->bd_disk);68 if (!base)69 return -ENODEV;70 /*71 * Man this is sick. We don't do a real disable but only downgrade72 * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses73 * BIODASDDISABLE to disable accesses to the device via the block74 * device layer but it still wants to do i/o on the device by75 * using the BIODASDFMT ioctl. Therefore the correct state for the76 * device is DASD_STATE_BASIC that allows to do basic i/o.77 */78 dasd_set_target_state(base, DASD_STATE_BASIC);79 /*80 * Set i_size to zero, since read, write, etc. check against this81 * value.82 */83 set_capacity(bdev->bd_disk, 0);84 dasd_put_device(base);85 return 0;86}87 88/*89 * Quiesce device.90 */91static int dasd_ioctl_quiesce(struct dasd_block *block)92{93 unsigned long flags;94 struct dasd_device *base;95 96 base = block->base;97 if (!capable (CAP_SYS_ADMIN))98 return -EACCES;99 100 pr_info("%s: The DASD has been put in the quiesce "101 "state\n", dev_name(&base->cdev->dev));102 spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);103 dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);104 spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);105 return 0;106}107 108 109/*110 * Resume device.111 */112static int dasd_ioctl_resume(struct dasd_block *block)113{114 unsigned long flags;115 struct dasd_device *base;116 117 base = block->base;118 if (!capable (CAP_SYS_ADMIN))119 return -EACCES;120 121 pr_info("%s: I/O operations have been resumed "122 "on the DASD\n", dev_name(&base->cdev->dev));123 spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);124 dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE);125 spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);126 127 dasd_schedule_block_bh(block);128 dasd_schedule_device_bh(base);129 return 0;130}131 132/*133 * Abort all failfast I/O on a device.134 */135static int dasd_ioctl_abortio(struct dasd_block *block)136{137 unsigned long flags;138 struct dasd_device *base;139 struct dasd_ccw_req *cqr, *n;140 141 base = block->base;142 if (!capable(CAP_SYS_ADMIN))143 return -EACCES;144 145 if (test_and_set_bit(DASD_FLAG_ABORTALL, &base->flags))146 return 0;147 DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag set");148 149 spin_lock_irqsave(&block->request_queue_lock, flags);150 spin_lock(&block->queue_lock);151 list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {152 if (test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&153 cqr->callback_data &&154 cqr->callback_data != DASD_SLEEPON_START_TAG &&155 cqr->callback_data != DASD_SLEEPON_END_TAG) {156 spin_unlock(&block->queue_lock);157 blk_abort_request(cqr->callback_data);158 spin_lock(&block->queue_lock);159 }160 }161 spin_unlock(&block->queue_lock);162 spin_unlock_irqrestore(&block->request_queue_lock, flags);163 164 dasd_schedule_block_bh(block);165 return 0;166}167 168/*169 * Allow I/O on a device170 */171static int dasd_ioctl_allowio(struct dasd_block *block)172{173 struct dasd_device *base;174 175 base = block->base;176 if (!capable(CAP_SYS_ADMIN))177 return -EACCES;178 179 if (test_and_clear_bit(DASD_FLAG_ABORTALL, &base->flags))180 DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag unset");181 182 return 0;183}184 185/*186 * performs formatting of _device_ according to _fdata_187 * Note: The discipline's format_function is assumed to deliver formatting188 * commands to format multiple units of the device. In terms of the ECKD189 * devices this means CCWs are generated to format multiple tracks.190 */191static int192dasd_format(struct dasd_block *block, struct format_data_t *fdata)193{194 struct dasd_device *base;195 int rc;196 197 base = block->base;198 if (base->discipline->format_device == NULL)199 return -EPERM;200 201 if (base->state != DASD_STATE_BASIC) {202 pr_warn("%s: The DASD cannot be formatted while it is enabled\n",203 dev_name(&base->cdev->dev));204 return -EBUSY;205 }206 207 DBF_DEV_EVENT(DBF_NOTICE, base,208 "formatting units %u to %u (%u B blocks) flags %u",209 fdata->start_unit,210 fdata->stop_unit, fdata->blksize, fdata->intensity);211 212 /* Since dasdfmt keeps the device open after it was disabled,213 * there still exists an inode for this device.214 * We must update i_blkbits, otherwise we might get errors when215 * enabling the device later.216 */217 if (fdata->start_unit == 0) {218 block->gdp->part0->bd_mapping->host->i_blkbits =219 blksize_bits(fdata->blksize);220 }221 222 rc = base->discipline->format_device(base, fdata, 1);223 if (rc == -EAGAIN)224 rc = base->discipline->format_device(base, fdata, 0);225 226 return rc;227}228 229static int dasd_check_format(struct dasd_block *block,230 struct format_check_t *cdata)231{232 struct dasd_device *base;233 int rc;234 235 base = block->base;236 if (!base->discipline->check_device_format)237 return -ENOTTY;238 239 rc = base->discipline->check_device_format(base, cdata, 1);240 if (rc == -EAGAIN)241 rc = base->discipline->check_device_format(base, cdata, 0);242 243 return rc;244}245 246/*247 * Format device.248 */249static int250dasd_ioctl_format(struct block_device *bdev, void __user *argp)251{252 struct dasd_device *base;253 struct format_data_t fdata;254 int rc;255 256 if (!capable(CAP_SYS_ADMIN))257 return -EACCES;258 if (!argp)259 return -EINVAL;260 base = dasd_device_from_gendisk(bdev->bd_disk);261 if (!base)262 return -ENODEV;263 if (base->features & DASD_FEATURE_READONLY ||264 test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {265 dasd_put_device(base);266 return -EROFS;267 }268 if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) {269 dasd_put_device(base);270 return -EFAULT;271 }272 if (bdev_is_partition(bdev)) {273 pr_warn("%s: The specified DASD is a partition and cannot be formatted\n",274 dev_name(&base->cdev->dev));275 dasd_put_device(base);276 return -EINVAL;277 }278 rc = dasd_format(base->block, &fdata);279 dasd_put_device(base);280 281 return rc;282}283 284/*285 * Check device format286 */287static int dasd_ioctl_check_format(struct block_device *bdev, void __user *argp)288{289 struct format_check_t cdata;290 struct dasd_device *base;291 int rc = 0;292 293 if (!argp)294 return -EINVAL;295 296 base = dasd_device_from_gendisk(bdev->bd_disk);297 if (!base)298 return -ENODEV;299 if (bdev_is_partition(bdev)) {300 pr_warn("%s: The specified DASD is a partition and cannot be checked\n",301 dev_name(&base->cdev->dev));302 rc = -EINVAL;303 goto out_err;304 }305 306 if (copy_from_user(&cdata, argp, sizeof(cdata))) {307 rc = -EFAULT;308 goto out_err;309 }310 311 rc = dasd_check_format(base->block, &cdata);312 if (rc)313 goto out_err;314 315 if (copy_to_user(argp, &cdata, sizeof(cdata)))316 rc = -EFAULT;317 318out_err:319 dasd_put_device(base);320 321 return rc;322}323 324static int dasd_release_space(struct dasd_device *device,325 struct format_data_t *rdata)326{327 if (!device->discipline->is_ese && !device->discipline->is_ese(device))328 return -ENOTSUPP;329 if (!device->discipline->release_space)330 return -ENOTSUPP;331 332 return device->discipline->release_space(device, rdata);333}334 335/*336 * Release allocated space337 */338static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp)339{340 struct format_data_t rdata;341 struct dasd_device *base;342 int rc = 0;343 344 if (!capable(CAP_SYS_ADMIN))345 return -EACCES;346 if (!argp)347 return -EINVAL;348 349 base = dasd_device_from_gendisk(bdev->bd_disk);350 if (!base)351 return -ENODEV;352 if (base->features & DASD_FEATURE_READONLY ||353 test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {354 rc = -EROFS;355 goto out_err;356 }357 if (bdev_is_partition(bdev)) {358 pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n",359 dev_name(&base->cdev->dev));360 rc = -EINVAL;361 goto out_err;362 }363 364 if (copy_from_user(&rdata, argp, sizeof(rdata))) {365 rc = -EFAULT;366 goto out_err;367 }368 369 rc = dasd_release_space(base, &rdata);370 371out_err:372 dasd_put_device(base);373 374 return rc;375}376 377/*378 * Swap driver iternal copy relation.379 */380static int381dasd_ioctl_copy_pair_swap(struct block_device *bdev, void __user *argp)382{383 struct dasd_copypair_swap_data_t data;384 struct dasd_device *device;385 int rc;386 387 if (!capable(CAP_SYS_ADMIN))388 return -EACCES;389 390 device = dasd_device_from_gendisk(bdev->bd_disk);391 if (!device)392 return -ENODEV;393 394 if (copy_from_user(&data, argp, sizeof(struct dasd_copypair_swap_data_t))) {395 dasd_put_device(device);396 return -EFAULT;397 }398 if (memchr_inv(data.reserved, 0, sizeof(data.reserved))) {399 pr_warn("%s: Invalid swap data specified\n",400 dev_name(&device->cdev->dev));401 dasd_put_device(device);402 return DASD_COPYPAIRSWAP_INVALID;403 }404 if (bdev_is_partition(bdev)) {405 pr_warn("%s: The specified DASD is a partition and cannot be swapped\n",406 dev_name(&device->cdev->dev));407 dasd_put_device(device);408 return DASD_COPYPAIRSWAP_INVALID;409 }410 if (!device->copy) {411 pr_warn("%s: The specified DASD has no copy pair set up\n",412 dev_name(&device->cdev->dev));413 dasd_put_device(device);414 return -ENODEV;415 }416 if (!device->discipline->copy_pair_swap) {417 dasd_put_device(device);418 return -EOPNOTSUPP;419 }420 rc = device->discipline->copy_pair_swap(device, data.primary,421 data.secondary);422 dasd_put_device(device);423 424 return rc;425}426 427#ifdef CONFIG_DASD_PROFILE428/*429 * Reset device profile information430 */431static int dasd_ioctl_reset_profile(struct dasd_block *block)432{433 dasd_profile_reset(&block->profile);434 return 0;435}436 437/*438 * Return device profile information439 */440static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)441{442 struct dasd_profile_info_t *data;443 int rc = 0;444 445 data = kmalloc(sizeof(*data), GFP_KERNEL);446 if (!data)447 return -ENOMEM;448 449 spin_lock_bh(&block->profile.lock);450 if (block->profile.data) {451 data->dasd_io_reqs = block->profile.data->dasd_io_reqs;452 data->dasd_io_sects = block->profile.data->dasd_io_sects;453 memcpy(data->dasd_io_secs, block->profile.data->dasd_io_secs,454 sizeof(data->dasd_io_secs));455 memcpy(data->dasd_io_times, block->profile.data->dasd_io_times,456 sizeof(data->dasd_io_times));457 memcpy(data->dasd_io_timps, block->profile.data->dasd_io_timps,458 sizeof(data->dasd_io_timps));459 memcpy(data->dasd_io_time1, block->profile.data->dasd_io_time1,460 sizeof(data->dasd_io_time1));461 memcpy(data->dasd_io_time2, block->profile.data->dasd_io_time2,462 sizeof(data->dasd_io_time2));463 memcpy(data->dasd_io_time2ps,464 block->profile.data->dasd_io_time2ps,465 sizeof(data->dasd_io_time2ps));466 memcpy(data->dasd_io_time3, block->profile.data->dasd_io_time3,467 sizeof(data->dasd_io_time3));468 memcpy(data->dasd_io_nr_req,469 block->profile.data->dasd_io_nr_req,470 sizeof(data->dasd_io_nr_req));471 spin_unlock_bh(&block->profile.lock);472 } else {473 spin_unlock_bh(&block->profile.lock);474 rc = -EIO;475 goto out;476 }477 if (copy_to_user(argp, data, sizeof(*data)))478 rc = -EFAULT;479out:480 kfree(data);481 return rc;482}483#else484static int dasd_ioctl_reset_profile(struct dasd_block *block)485{486 return -ENOTTY;487}488 489static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)490{491 return -ENOTTY;492}493#endif494 495/*496 * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.497 */498static int __dasd_ioctl_information(struct dasd_block *block,499 struct dasd_information2_t *dasd_info)500{501 struct subchannel_id sch_id;502 struct ccw_dev_id dev_id;503 struct dasd_device *base;504 struct ccw_device *cdev;505 struct list_head *l;506 unsigned long flags;507 int rc;508 509 base = block->base;510 if (!base->discipline || !base->discipline->fill_info)511 return -EINVAL;512 513 rc = base->discipline->fill_info(base, dasd_info);514 if (rc)515 return rc;516 517 cdev = base->cdev;518 ccw_device_get_id(cdev, &dev_id);519 ccw_device_get_schid(cdev, &sch_id);520 521 dasd_info->devno = dev_id.devno;522 dasd_info->schid = sch_id.sch_no;523 dasd_info->cu_type = cdev->id.cu_type;524 dasd_info->cu_model = cdev->id.cu_model;525 dasd_info->dev_type = cdev->id.dev_type;526 dasd_info->dev_model = cdev->id.dev_model;527 dasd_info->status = base->state;528 /*529 * The open_count is increased for every opener, that includes530 * the blkdev_get in dasd_scan_partitions.531 * This must be hidden from user-space.532 */533 dasd_info->open_count = atomic_read(&block->open_count);534 if (!block->bdev_file)535 dasd_info->open_count++;536 537 /*538 * check if device is really formatted539 * LDL / CDL was returned by 'fill_info'540 */541 if ((base->state < DASD_STATE_READY) ||542 (dasd_check_blocksize(block->bp_block)))543 dasd_info->format = DASD_FORMAT_NONE;544 545 dasd_info->features |=546 ((base->features & DASD_FEATURE_READONLY) != 0);547 548 memcpy(dasd_info->type, base->discipline->name, 4);549 550 spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);551 list_for_each(l, &base->ccw_queue)552 dasd_info->chanq_len++;553 spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);554 return 0;555}556 557static int dasd_ioctl_information(struct dasd_block *block, void __user *argp,558 size_t copy_size)559{560 struct dasd_information2_t *dasd_info;561 int error;562 563 dasd_info = kzalloc(sizeof(*dasd_info), GFP_KERNEL);564 if (!dasd_info)565 return -ENOMEM;566 567 error = __dasd_ioctl_information(block, dasd_info);568 if (!error && copy_to_user(argp, dasd_info, copy_size))569 error = -EFAULT;570 kfree(dasd_info);571 return error;572}573 574/*575 * Set read only576 */577int dasd_set_read_only(struct block_device *bdev, bool ro)578{579 struct dasd_device *base;580 int rc;581 582 /* do not manipulate hardware state for partitions */583 if (bdev_is_partition(bdev))584 return 0;585 586 base = dasd_device_from_gendisk(bdev->bd_disk);587 if (!base)588 return -ENODEV;589 if (!ro && test_bit(DASD_FLAG_DEVICE_RO, &base->flags))590 rc = -EROFS;591 else592 rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, ro);593 dasd_put_device(base);594 return rc;595}596 597static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,598 struct cmbdata __user *argp)599{600 size_t size = _IOC_SIZE(cmd);601 struct cmbdata data;602 int ret;603 604 ret = cmf_readall(block->base->cdev, &data);605 if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))606 return -EFAULT;607 return ret;608}609 610int dasd_ioctl(struct block_device *bdev, blk_mode_t mode,611 unsigned int cmd, unsigned long arg)612{613 struct dasd_block *block;614 struct dasd_device *base;615 void __user *argp;616 int rc;617 618 if (is_compat_task())619 argp = compat_ptr(arg);620 else621 argp = (void __user *)arg;622 623 if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg)624 return -EINVAL;625 626 base = dasd_device_from_gendisk(bdev->bd_disk);627 if (!base)628 return -ENODEV;629 block = base->block;630 rc = 0;631 switch (cmd) {632 case BIODASDDISABLE:633 rc = dasd_ioctl_disable(bdev);634 break;635 case BIODASDENABLE:636 rc = dasd_ioctl_enable(bdev);637 break;638 case BIODASDQUIESCE:639 rc = dasd_ioctl_quiesce(block);640 break;641 case BIODASDRESUME:642 rc = dasd_ioctl_resume(block);643 break;644 case BIODASDABORTIO:645 rc = dasd_ioctl_abortio(block);646 break;647 case BIODASDALLOWIO:648 rc = dasd_ioctl_allowio(block);649 break;650 case BIODASDFMT:651 rc = dasd_ioctl_format(bdev, argp);652 break;653 case BIODASDCHECKFMT:654 rc = dasd_ioctl_check_format(bdev, argp);655 break;656 case BIODASDINFO:657 rc = dasd_ioctl_information(block, argp,658 sizeof(struct dasd_information_t));659 break;660 case BIODASDINFO2:661 rc = dasd_ioctl_information(block, argp,662 sizeof(struct dasd_information2_t));663 break;664 case BIODASDPRRD:665 rc = dasd_ioctl_read_profile(block, argp);666 break;667 case BIODASDPRRST:668 rc = dasd_ioctl_reset_profile(block);669 break;670 case DASDAPIVER:671 rc = dasd_ioctl_api_version(argp);672 break;673 case BIODASDCMFENABLE:674 rc = enable_cmf(base->cdev);675 break;676 case BIODASDCMFDISABLE:677 rc = disable_cmf(base->cdev);678 break;679 case BIODASDREADALLCMB:680 rc = dasd_ioctl_readall_cmb(block, cmd, argp);681 break;682 case BIODASDRAS:683 rc = dasd_ioctl_release_space(bdev, argp);684 break;685 case BIODASDCOPYPAIRSWAP:686 rc = dasd_ioctl_copy_pair_swap(bdev, argp);687 break;688 default:689 /* if the discipline has an ioctl method try it. */690 rc = -ENOTTY;691 if (base->discipline->ioctl)692 rc = base->discipline->ioctl(block, cmd, argp);693 }694 dasd_put_device(base);695 return rc;696}697 698 699/**700 * dasd_biodasdinfo() - fill out the dasd information structure701 * @disk: [in] pointer to gendisk structure that references a DASD702 * @info: [out] pointer to the dasd_information2_t structure703 *704 * Provide access to DASD specific information.705 * The gendisk structure is checked if it belongs to the DASD driver by706 * comparing the gendisk->fops pointer.707 * If it does not belong to the DASD driver -EINVAL is returned.708 * Otherwise the provided dasd_information2_t structure is filled out.709 *710 * Returns:711 * %0 on success and a negative error value on failure.712 */713int dasd_biodasdinfo(struct gendisk *disk, struct dasd_information2_t *info)714{715 struct dasd_device *base;716 int error;717 718 if (disk->fops != &dasd_device_operations)719 return -EINVAL;720 721 base = dasd_device_from_gendisk(disk);722 if (!base)723 return -ENODEV;724 error = __dasd_ioctl_information(base->block, info);725 dasd_put_device(base);726 return error;727}728/* export that symbol_get in partition detection is possible */729EXPORT_SYMBOL_GPL(dasd_biodasdinfo);730