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