1f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/blkdev.h>
2f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/blkpg.h>
3f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/blktrace_api.h>
4f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/cdrom.h>
5f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/compat.h>
6f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/elevator.h>
7f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/fd.h>
8f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/hdreg.h>
95a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
10f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/syscalls.h>
11f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/types.h>
12f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#include <linux/uaccess.h>
13f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
14f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmannstatic int compat_put_ushort(unsigned long arg, unsigned short val)
15f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann{
16f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	return put_user(val, (unsigned short __user *)compat_ptr(arg));
17f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann}
18f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
19f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmannstatic int compat_put_int(unsigned long arg, int val)
20f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann{
21f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	return put_user(val, (compat_int_t __user *)compat_ptr(arg));
22f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann}
23f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
24ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersenstatic int compat_put_uint(unsigned long arg, unsigned int val)
25ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen{
26ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen	return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
27ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen}
28ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen
29f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmannstatic int compat_put_long(unsigned long arg, long val)
30f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann{
31f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	return put_user(val, (compat_long_t __user *)compat_ptr(arg));
32f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann}
33f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
34f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmannstatic int compat_put_ulong(unsigned long arg, compat_ulong_t val)
35f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann{
36f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
37f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann}
38f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
39f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmannstatic int compat_put_u64(unsigned long arg, u64 val)
40f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann{
41f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	return put_user(val, (compat_u64 __user *)compat_ptr(arg));
42f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann}
43f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
449617db085c119879cd371e3212806a15596e121aArnd Bergmannstruct compat_hd_geometry {
459617db085c119879cd371e3212806a15596e121aArnd Bergmann	unsigned char heads;
469617db085c119879cd371e3212806a15596e121aArnd Bergmann	unsigned char sectors;
479617db085c119879cd371e3212806a15596e121aArnd Bergmann	unsigned short cylinders;
489617db085c119879cd371e3212806a15596e121aArnd Bergmann	u32 start;
499617db085c119879cd371e3212806a15596e121aArnd Bergmann};
509617db085c119879cd371e3212806a15596e121aArnd Bergmann
519617db085c119879cd371e3212806a15596e121aArnd Bergmannstatic int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
529617db085c119879cd371e3212806a15596e121aArnd Bergmann			struct compat_hd_geometry __user *ugeo)
539617db085c119879cd371e3212806a15596e121aArnd Bergmann{
549617db085c119879cd371e3212806a15596e121aArnd Bergmann	struct hd_geometry geo;
559617db085c119879cd371e3212806a15596e121aArnd Bergmann	int ret;
569617db085c119879cd371e3212806a15596e121aArnd Bergmann
579617db085c119879cd371e3212806a15596e121aArnd Bergmann	if (!ugeo)
589617db085c119879cd371e3212806a15596e121aArnd Bergmann		return -EINVAL;
599617db085c119879cd371e3212806a15596e121aArnd Bergmann	if (!disk->fops->getgeo)
609617db085c119879cd371e3212806a15596e121aArnd Bergmann		return -ENOTTY;
619617db085c119879cd371e3212806a15596e121aArnd Bergmann
628b0d77f13192678019f07cbc6b3338d6d91f1cf4Cong Wang	memset(&geo, 0, sizeof(geo));
639617db085c119879cd371e3212806a15596e121aArnd Bergmann	/*
649617db085c119879cd371e3212806a15596e121aArnd Bergmann	 * We need to set the startsect first, the driver may
659617db085c119879cd371e3212806a15596e121aArnd Bergmann	 * want to override it.
669617db085c119879cd371e3212806a15596e121aArnd Bergmann	 */
679617db085c119879cd371e3212806a15596e121aArnd Bergmann	geo.start = get_start_sect(bdev);
689617db085c119879cd371e3212806a15596e121aArnd Bergmann	ret = disk->fops->getgeo(bdev, &geo);
699617db085c119879cd371e3212806a15596e121aArnd Bergmann	if (ret)
709617db085c119879cd371e3212806a15596e121aArnd Bergmann		return ret;
719617db085c119879cd371e3212806a15596e121aArnd Bergmann
729617db085c119879cd371e3212806a15596e121aArnd Bergmann	ret = copy_to_user(ugeo, &geo, 4);
733ddc5b46a8e90f3c9251338b60191d0a804b0d92Mathieu Desnoyers	ret |= put_user(geo.start, &ugeo->start);
749617db085c119879cd371e3212806a15596e121aArnd Bergmann	if (ret)
759617db085c119879cd371e3212806a15596e121aArnd Bergmann		ret = -EFAULT;
769617db085c119879cd371e3212806a15596e121aArnd Bergmann
779617db085c119879cd371e3212806a15596e121aArnd Bergmann	return ret;
789617db085c119879cd371e3212806a15596e121aArnd Bergmann}
799617db085c119879cd371e3212806a15596e121aArnd Bergmann
8033c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Virostatic int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
8133c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		unsigned int cmd, unsigned long arg)
829617db085c119879cd371e3212806a15596e121aArnd Bergmann{
839617db085c119879cd371e3212806a15596e121aArnd Bergmann	mm_segment_t old_fs = get_fs();
849617db085c119879cd371e3212806a15596e121aArnd Bergmann	unsigned long kval;
859617db085c119879cd371e3212806a15596e121aArnd Bergmann	unsigned int __user *uvp;
869617db085c119879cd371e3212806a15596e121aArnd Bergmann	int error;
879617db085c119879cd371e3212806a15596e121aArnd Bergmann
889617db085c119879cd371e3212806a15596e121aArnd Bergmann	set_fs(KERNEL_DS);
8933c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro	error = __blkdev_driver_ioctl(bdev, mode,
909617db085c119879cd371e3212806a15596e121aArnd Bergmann				cmd, (unsigned long)(&kval));
919617db085c119879cd371e3212806a15596e121aArnd Bergmann	set_fs(old_fs);
929617db085c119879cd371e3212806a15596e121aArnd Bergmann
939617db085c119879cd371e3212806a15596e121aArnd Bergmann	if (error == 0) {
949617db085c119879cd371e3212806a15596e121aArnd Bergmann		uvp = compat_ptr(arg);
959617db085c119879cd371e3212806a15596e121aArnd Bergmann		if (put_user(kval, uvp))
969617db085c119879cd371e3212806a15596e121aArnd Bergmann			error = -EFAULT;
979617db085c119879cd371e3212806a15596e121aArnd Bergmann	}
989617db085c119879cd371e3212806a15596e121aArnd Bergmann	return error;
999617db085c119879cd371e3212806a15596e121aArnd Bergmann}
1009617db085c119879cd371e3212806a15596e121aArnd Bergmann
101b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmannstruct compat_cdrom_read_audio {
102b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	union cdrom_addr	addr;
103b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	u8			addr_format;
104b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_int_t		nframes;
105b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_caddr_t		buf;
106b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann};
107b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
108b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmannstruct compat_cdrom_generic_command {
109b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	unsigned char	cmd[CDROM_PACKET_SIZE];
110b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_caddr_t	buffer;
111b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_uint_t	buflen;
112b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_int_t	stat;
113b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_caddr_t	sense;
114b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	unsigned char	data_direction;
115b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_int_t	quiet;
116b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_int_t	timeout;
117b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	compat_caddr_t	reserved[1];
118b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann};
119b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
12033c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Virostatic int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
12133c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		unsigned int cmd, unsigned long arg)
122b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann{
123b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	struct cdrom_read_audio __user *cdread_audio;
124b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	struct compat_cdrom_read_audio __user *cdread_audio32;
125b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	__u32 data;
126b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	void __user *datap;
127b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
128b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
129b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	cdread_audio32 = compat_ptr(arg);
130b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
131b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	if (copy_in_user(&cdread_audio->addr,
132b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann			 &cdread_audio32->addr,
133b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann			 (sizeof(*cdread_audio32) -
134b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann			  sizeof(compat_caddr_t))))
135b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann		return -EFAULT;
136b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
137b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	if (get_user(data, &cdread_audio32->buf))
138b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann		return -EFAULT;
139b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	datap = compat_ptr(data);
140b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	if (put_user(datap, &cdread_audio->buf))
141b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann		return -EFAULT;
142b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
14333c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro	return __blkdev_driver_ioctl(bdev, mode, cmd,
144b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann			(unsigned long)cdread_audio);
145b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann}
146b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
14733c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Virostatic int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
14833c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		unsigned int cmd, unsigned long arg)
149b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann{
150b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	struct cdrom_generic_command __user *cgc;
151b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	struct compat_cdrom_generic_command __user *cgc32;
152b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	u32 data;
153b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	unsigned char dir;
154b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	int itmp;
155b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
156b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	cgc = compat_alloc_user_space(sizeof(*cgc));
157b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	cgc32 = compat_ptr(arg);
158b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
159b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
160b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    get_user(data, &cgc32->buffer) ||
161b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    put_user(compat_ptr(data), &cgc->buffer) ||
162b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    copy_in_user(&cgc->buflen, &cgc32->buflen,
163b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann			 (sizeof(unsigned int) + sizeof(int))) ||
164b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    get_user(data, &cgc32->sense) ||
165b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    put_user(compat_ptr(data), &cgc->sense) ||
166b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    get_user(dir, &cgc32->data_direction) ||
167b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    put_user(dir, &cgc->data_direction) ||
168b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    get_user(itmp, &cgc32->quiet) ||
169b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    put_user(itmp, &cgc->quiet) ||
170b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    get_user(itmp, &cgc32->timeout) ||
171b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    put_user(itmp, &cgc->timeout) ||
172b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    get_user(data, &cgc32->reserved[0]) ||
173b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	    put_user(compat_ptr(data), &cgc->reserved[0]))
174b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann		return -EFAULT;
175b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
17633c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro	return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
177b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann}
178b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
17918cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmannstruct compat_blkpg_ioctl_arg {
18018cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	compat_int_t op;
18118cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	compat_int_t flags;
18218cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	compat_int_t datalen;
18318cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	compat_caddr_t data;
18418cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann};
18518cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann
18656b26add02b4bdea81d5e0ebda60db1fe3311ad4Al Virostatic int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
18718cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann		unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
18818cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann{
18918cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
19018cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	compat_caddr_t udata;
19118cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	compat_int_t n;
19218cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	int err;
19318cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann
19418cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err = get_user(n, &ua32->op);
19518cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= put_user(n, &a->op);
19618cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= get_user(n, &ua32->flags);
19718cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= put_user(n, &a->flags);
19818cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= get_user(n, &ua32->datalen);
19918cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= put_user(n, &a->datalen);
20018cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= get_user(udata, &ua32->data);
20118cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	err |= put_user(compat_ptr(udata), &a->data);
20218cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann	if (err)
20318cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann		return err;
20418cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann
20556b26add02b4bdea81d5e0ebda60db1fe3311ad4Al Viro	return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
20618cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann}
20718cf7f8723d913ce02bea43e468bebdd07bc880cArnd Bergmann
208f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#define BLKBSZGET_32		_IOR(0x12, 112, int)
209f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#define BLKBSZSET_32		_IOW(0x12, 113, int)
210f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann#define BLKGETSIZE64_32		_IOR(0x12, 114, int)
211f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
2121ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmannstruct compat_floppy_drive_params {
2131ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	char		cmos;
2141ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	max_dtr;
2151ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	hlt;
2161ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	hut;
2171ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	srt;
2181ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	spinup;
2191ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	spindown;
2201ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	spindown_offset;
2211ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	select_delay;
2221ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	rps;
2231ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	tracks;
2241ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	timeout;
2251ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	interleave_sect;
2261ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	struct floppy_max_errors max_errors;
2271ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	char		flags;
2281ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	char		read_track;
2291ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	short		autodetect[8];
2301ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	checkfreq;
2311ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	native_format;
2321ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann};
2331ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
2341ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmannstruct compat_floppy_drive_struct {
2351ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	signed char	flags;
2361ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	spinup_date;
2371ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	select_date;
2381ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	first_read_date;
2391ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	short		probed_format;
2401ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	short		track;
2411ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	short		maxblock;
2421ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	short		maxtrack;
2431ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	generation;
2441ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	keep_data;
2451ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	fd_ref;
2461ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	fd_device;
2471ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	last_checked;
2481ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_caddr_t dmabuf;
2491ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	bufblocks;
2501ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann};
2511ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
2521ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmannstruct compat_floppy_fdc_state {
2531ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	spec1;
2541ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	spec2;
2551ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	dtr;
2561ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	version;
2571ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	dor;
2581ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	address;
2591ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	rawcmd:2;
2601ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	reset:1;
2611ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	need_configure:1;
2621ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	perp_mode:2;
2631ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	has_fifo:1;
2641ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	driver_version;
2651ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned char	track[4];
2661ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann};
2671ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
2681ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmannstruct compat_floppy_write_errors {
2691ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	write_errors;
2701ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	first_error_sector;
2711ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	first_error_generation;
2721ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_ulong_t	last_error_sector;
2731ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_int_t	last_error_generation;
2741ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	compat_uint_t	badness;
2751ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann};
2761ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
2771ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
2781ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
2791ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
2801ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
2811ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
2821ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
2831ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
2841ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define FDWERRORGET32  _IOR(2, 0x17, struct compat_floppy_write_errors)
2851ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
2861ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmannstatic struct {
2871ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	cmd32;
2881ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int	cmd;
2891ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann} fd_ioctl_trans_table[] = {
2901ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDSETPRM32, FDSETPRM },
2911ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDDEFPRM32, FDDEFPRM },
2921ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDGETPRM32, FDGETPRM },
2931ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDSETDRVPRM32, FDSETDRVPRM },
2941ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDGETDRVPRM32, FDGETDRVPRM },
2951ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDGETDRVSTAT32, FDGETDRVSTAT },
2961ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
2971ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDGETFDCSTAT32, FDGETFDCSTAT },
2981ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{ FDWERRORGET32, FDWERRORGET }
2991ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann};
3001ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
3011ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
3021ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
30333c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Virostatic int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
30433c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		unsigned int cmd, unsigned long arg)
3051ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann{
3061ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	mm_segment_t old_fs = get_fs();
3071ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	void *karg = NULL;
3081ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	unsigned int kcmd = 0;
3091ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	int i, err;
3101ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
3111ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
3121ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (cmd == fd_ioctl_trans_table[i].cmd32) {
3131ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			kcmd = fd_ioctl_trans_table[i].cmd;
3141ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			break;
3151ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		}
3161ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	if (!kcmd)
3171ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		return -EINVAL;
3181ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
3191ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	switch (cmd) {
3201ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDSETPRM32:
3211ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDDEFPRM32:
3221ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETPRM32:
3231ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
3241ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		compat_uptr_t name;
3251ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_struct __user *uf;
3261ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_struct *f;
3271ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
3281ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		uf = compat_ptr(arg);
3291ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
3301ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (!karg)
3311ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			return -ENOMEM;
3321ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (cmd == FDGETPRM32)
3331ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			break;
3341ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __get_user(f->size, &uf->size);
3351ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->sect, &uf->sect);
3361ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->head, &uf->head);
3371ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->track, &uf->track);
3381ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->stretch, &uf->stretch);
3391ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->gap, &uf->gap);
3401ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->rate, &uf->rate);
3411ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->spec1, &uf->spec1);
3421ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->fmt_gap, &uf->fmt_gap);
3431ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(name, &uf->name);
3441ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		f->name = compat_ptr(name);
3451ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (err) {
3461ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			err = -EFAULT;
3471ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			goto out;
3481ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		}
3491ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
3501ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
3511ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDSETDRVPRM32:
3521ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETDRVPRM32:
3531ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
3541ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_drive_params __user *uf;
3551ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_drive_params *f;
3561ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
3571ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		uf = compat_ptr(arg);
3581ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
3591ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (!karg)
3601ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			return -ENOMEM;
3611ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (cmd == FDGETDRVPRM32)
3621ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			break;
3631ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __get_user(f->cmos, &uf->cmos);
3641ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->max_dtr, &uf->max_dtr);
3651ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->hlt, &uf->hlt);
3661ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->hut, &uf->hut);
3671ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->srt, &uf->srt);
3681ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->spinup, &uf->spinup);
3691ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->spindown, &uf->spindown);
3701ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->spindown_offset, &uf->spindown_offset);
3711ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->select_delay, &uf->select_delay);
3721ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->rps, &uf->rps);
3731ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->tracks, &uf->tracks);
3741ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->timeout, &uf->timeout);
3751ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->interleave_sect, &uf->interleave_sect);
3761ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
3771ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->flags, &uf->flags);
3781ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->read_track, &uf->read_track);
3791ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
3801ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->checkfreq, &uf->checkfreq);
3811ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __get_user(f->native_format, &uf->native_format);
3821ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (err) {
3831ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			err = -EFAULT;
3841ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			goto out;
3851ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		}
3861ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
3871ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
3881ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETDRVSTAT32:
3891ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDPOLLDRVSTAT32:
3901ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
3911ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (!karg)
3921ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			return -ENOMEM;
3931ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
3941ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETFDCSTAT32:
3951ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
3961ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (!karg)
3971ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			return -ENOMEM;
3981ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
3991ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDWERRORGET32:
4001ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
4011ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		if (!karg)
4021ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann			return -ENOMEM;
4031ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
4041ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	default:
4051ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		return -EINVAL;
4061ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
4071ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	set_fs(KERNEL_DS);
40833c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro	err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
4091ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	set_fs(old_fs);
4101ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	if (err)
4111ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		goto out;
4121ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	switch (cmd) {
4131ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETPRM32:
4141ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
4151ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_struct *f = karg;
4161ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_struct __user *uf = compat_ptr(arg);
4171ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
4181ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __put_user(f->size, &uf->size);
4191ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->sect, &uf->sect);
4201ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->head, &uf->head);
4211ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->track, &uf->track);
4221ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->stretch, &uf->stretch);
4231ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->gap, &uf->gap);
4241ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->rate, &uf->rate);
4251ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->spec1, &uf->spec1);
4261ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->fmt_gap, &uf->fmt_gap);
4271ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
4281ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
4291ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
4301ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETDRVPRM32:
4311ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
4321ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_drive_params __user *uf;
4331ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_drive_params *f = karg;
4341ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
4351ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		uf = compat_ptr(arg);
4361ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __put_user(f->cmos, &uf->cmos);
4371ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->max_dtr, &uf->max_dtr);
4381ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->hlt, &uf->hlt);
4391ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->hut, &uf->hut);
4401ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->srt, &uf->srt);
4411ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->spinup, &uf->spinup);
4421ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->spindown, &uf->spindown);
4431ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->spindown_offset, &uf->spindown_offset);
4441ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->select_delay, &uf->select_delay);
4451ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->rps, &uf->rps);
4461ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->tracks, &uf->tracks);
4471ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->timeout, &uf->timeout);
4481ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->interleave_sect, &uf->interleave_sect);
4491ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
4501ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->flags, &uf->flags);
4511ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->read_track, &uf->read_track);
4521ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
4531ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->checkfreq, &uf->checkfreq);
4541ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->native_format, &uf->native_format);
4551ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
4561ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
4571ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETDRVSTAT32:
4581ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDPOLLDRVSTAT32:
4591ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
4601ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_drive_struct __user *uf;
4611ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_drive_struct *f = karg;
4621ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
4631ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		uf = compat_ptr(arg);
4641ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __put_user(f->flags, &uf->flags);
4651ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->spinup_date, &uf->spinup_date);
4661ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->select_date, &uf->select_date);
4671ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->first_read_date, &uf->first_read_date);
4681ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->probed_format, &uf->probed_format);
4691ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->track, &uf->track);
4701ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->maxblock, &uf->maxblock);
4711ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->maxtrack, &uf->maxtrack);
4721ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->generation, &uf->generation);
4731ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->keep_data, &uf->keep_data);
4741ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->fd_ref, &uf->fd_ref);
4751ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->fd_device, &uf->fd_device);
4761ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->last_checked, &uf->last_checked);
4771ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
4781ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
4791ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
4801ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
4811ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETFDCSTAT32:
4821ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
4831ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_fdc_state __user *uf;
4841ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_fdc_state *f = karg;
4851ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
4861ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		uf = compat_ptr(arg);
4871ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __put_user(f->spec1, &uf->spec1);
4881ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->spec2, &uf->spec2);
4891ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->dtr, &uf->dtr);
4901ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->version, &uf->version);
4911ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->dor, &uf->dor);
4921ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->address, &uf->address);
4931ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
4941ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann				   (char *)&f->address + sizeof(f->address), sizeof(int));
4951ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->driver_version, &uf->driver_version);
4961ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
4971ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
4981ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
4991ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDWERRORGET32:
5001ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	{
5011ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct compat_floppy_write_errors __user *uf;
5021ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		struct floppy_write_errors *f = karg;
5031ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
5041ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		uf = compat_ptr(arg);
5051ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = __put_user(f->write_errors, &uf->write_errors);
5061ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->first_error_sector, &uf->first_error_sector);
5071ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->first_error_generation, &uf->first_error_generation);
5081ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->last_error_sector, &uf->last_error_sector);
5091ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->last_error_generation, &uf->last_error_generation);
5101ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err |= __put_user(f->badness, &uf->badness);
5111ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
5121ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
5131ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	default:
5141ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		break;
5151ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	}
5161ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	if (err)
5171ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann		err = -EFAULT;
5181ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
5191ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmannout:
5201ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	kfree(karg);
5211ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	return err;
5221ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann}
5231ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann
52433c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Virostatic int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
52533c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro			unsigned cmd, unsigned long arg)
5267199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann{
52733013a881104304fcffe817f17f22a1588908037Philip Langdale	switch (cmd) {
5289617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_UNMASKINTR:
5299617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_MULTCOUNT:
5309617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_KEEPSETTINGS:
5319617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_32BIT:
5329617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_NOWERR:
5339617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_DMA:
5349617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_NICE:
5359617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_WCACHE:
5369617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_ACOUSTIC:
5379617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_ADDRESS:
5389617db085c119879cd371e3212806a15596e121aArnd Bergmann	case HDIO_GET_BUSSTATE:
53933c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		return compat_hdio_ioctl(bdev, mode, cmd, arg);
5401ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDSETPRM32:
5411ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDDEFPRM32:
5421ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETPRM32:
5431ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDSETDRVPRM32:
5441ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETDRVPRM32:
5451ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETDRVSTAT32:
5461ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDPOLLDRVSTAT32:
5471ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDGETFDCSTAT32:
5481ca91cd0336b05b91c51b403c9ed9d297813533fArnd Bergmann	case FDWERRORGET32:
54933c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		return compat_fd_ioctl(bdev, mode, cmd, arg);
550b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	case CDROMREADAUDIO:
55133c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		return compat_cdrom_read_audio(bdev, mode, cmd, arg);
552b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann	case CDROM_SEND_PACKET:
55333c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro		return compat_cdrom_generic_command(bdev, mode, cmd, arg);
554b3087cc4f31a66c8c7b63419e913ed9d34145f10Arnd Bergmann
5557199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/*
5567199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 * No handler required for the ones below, we just need to
5577199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 * convert arg to a 64 bit pointer.
5587199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 */
5597199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case BLKSECTSET:
5607199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/*
5617199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
5627199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 *         Some need translations, these do not.
5637199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 */
5647199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case HDIO_GET_IDENTITY:
5657199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case HDIO_DRIVE_TASK:
5667199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case HDIO_DRIVE_CMD:
5677199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
5687199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case 0x330:
5697199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/* 0x02 -- Floppy ioctls */
5707199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDMSGON:
5717199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDMSGOFF:
5727199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDSETEMSGTRESH:
5737199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDFLUSH:
5747199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDWERRORCLR:
5757199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDSETMAXERRS:
5767199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDGETMAXERRS:
5777199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDGETDRVTYP:
5787199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDEJECT:
5797199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDCLRPRM:
5807199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDFMTBEG:
5817199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDFMTEND:
5827199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDRESET:
5837199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDTWADDLE:
5847199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDFMTTRK:
5857199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case FDRAWCMD:
5867199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/* CDROM stuff */
5877199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMPAUSE:
5887199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMRESUME:
5897199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMPLAYMSF:
5907199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMPLAYTRKIND:
5917199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADTOCHDR:
5927199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADTOCENTRY:
5937199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMSTOP:
5947199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMSTART:
5957199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMEJECT:
5967199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMVOLCTRL:
5977199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMSUBCHNL:
5987199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMMULTISESSION:
5997199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROM_GET_MCN:
6007199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMRESET:
6017199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMVOLREAD:
6027199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMSEEK:
6037199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMPLAYBLK:
6047199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMCLOSETRAY:
6057199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROM_DISC_STATUS:
6067199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROM_CHANGER_NSLOTS:
6077199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROM_GET_CAPABILITY:
6087199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
6097199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 * not take a struct cdrom_read, instead they take a struct cdrom_msf
6107199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 * which is compatible.
6117199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	 */
6127199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADMODE2:
6137199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADMODE1:
6147199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADRAW:
6157199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADCOOKED:
6167199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case CDROMREADALL:
6177199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	/* DVD ioctls */
6187199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case DVD_READ_STRUCT:
6197199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case DVD_WRITE_STRUCT:
6207199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	case DVD_AUTH:
6217199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann		arg = (unsigned long)compat_ptr(arg);
6221c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	/* These intepret arg as an unsigned long, not as a pointer,
6231c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	 * so we must not do compat_ptr() conversion. */
6241c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_MULTCOUNT:
6251c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_UNMASKINTR:
6261c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_KEEPSETTINGS:
6271c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_32BIT:
6281c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_NOWERR:
6291c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_DMA:
6301c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_PIO_MODE:
6311c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_NICE:
6321c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_WCACHE:
6331c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_ACOUSTIC:
6341c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_BUSSTATE:
6351c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case HDIO_SET_ADDRESS:
6361c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROMEJECT_SW:
6371c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_SET_OPTIONS:
6381c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_CLEAR_OPTIONS:
6391c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_SELECT_SPEED:
6401c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_SELECT_DISC:
6411c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_MEDIA_CHANGED:
6421c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_DRIVE_STATUS:
6431c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_LOCKDOOR:
6441c925604e1038c7c65b91a92d14dc972b3a70a97Andreas Schwab	case CDROM_DEBUG:
6457199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann		break;
6467199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	default:
6477199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann		/* unknown ioctl number */
6487199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann		return -ENOIOCTLCMD;
6497199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann	}
6507199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann
65133c2dca4957bd0da3e1af7b96d0758d97e708ef6Al Viro	return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
6527199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann}
6537199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann
65445048d0961cdbf7ddfba906797ad8cb42489e070Al Viro/* Most of the generic ioctls are handled in the normal fallback path.
65545048d0961cdbf7ddfba906797ad8cb42489e070Al Viro   This assumes the blkdev's low level compat_ioctl always returns
65645048d0961cdbf7ddfba906797ad8cb42489e070Al Viro   ENOIOCTLCMD for unknown ioctls. */
65745048d0961cdbf7ddfba906797ad8cb42489e070Al Virolong compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
658f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann{
65945048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	int ret = -ENOIOCTLCMD;
66045048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	struct inode *inode = file->f_mapping->host;
66145048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	struct block_device *bdev = inode->i_bdev;
66245048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	struct gendisk *disk = bdev->bd_disk;
66345048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	fmode_t mode = file->f_mode;
664f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	struct backing_dev_info *bdi;
66545048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	loff_t size;
66663f264965947ac6299452711f614f086955b2515Akinobu Mita	unsigned int max_sectors;
66745048d0961cdbf7ddfba906797ad8cb42489e070Al Viro
668fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig	/*
669fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig	 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
670fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig	 * to updated it before every ioctl.
671fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig	 */
67245048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	if (file->f_flags & O_NDELAY)
673fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig		mode |= FMODE_NDELAY;
674fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig	else
675fd4ce1acd0f8558033b1a6968001552bd7671e6dChristoph Hellwig		mode &= ~FMODE_NDELAY;
676f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
677f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	switch (cmd) {
67845048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case HDIO_GETGEO:
67945048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
680ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen	case BLKPBSZGET:
681ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen		return compat_put_uint(arg, bdev_physical_block_size(bdev));
682ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen	case BLKIOMIN:
683ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen		return compat_put_uint(arg, bdev_io_min(bdev));
684ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen	case BLKIOOPT:
685ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen		return compat_put_uint(arg, bdev_io_opt(bdev));
686ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen	case BLKALIGNOFF:
687ac481c20ef8f6c6f2be75d581863f40c43874ef7Martin K. Petersen		return compat_put_int(arg, bdev_alignment_offset(bdev));
68898262f2762f0067375f83824d81ea929e37e6bfeMartin K. Petersen	case BLKDISCARDZEROES:
68998262f2762f0067375f83824d81ea929e37e6bfeMartin K. Petersen		return compat_put_uint(arg, bdev_discard_zeroes_data(bdev));
69045048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case BLKFLSBUF:
69145048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case BLKROSET:
69245048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case BLKDISCARD:
6938d57a98ccd0b4489003473979da8f5a1363ba7a3Adrian Hunter	case BLKSECDISCARD:
6943b3a1814d1703027f9867d0f5cbbfaf6c7482474Mikulas Patocka	case BLKZEROOUT:
69545048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	/*
69645048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	 * the ones below are implemented in blkdev_locked_ioctl,
69745048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	 * but we call blkdev_ioctl, which gets the lock for us
69845048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	 */
69945048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case BLKRRPART:
70056b26add02b4bdea81d5e0ebda60db1fe3311ad4Al Viro		return blkdev_ioctl(bdev, mode, cmd,
70145048d0961cdbf7ddfba906797ad8cb42489e070Al Viro				(unsigned long)compat_ptr(arg));
70245048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case BLKBSZSET_32:
70356b26add02b4bdea81d5e0ebda60db1fe3311ad4Al Viro		return blkdev_ioctl(bdev, mode, BLKBSZSET,
70445048d0961cdbf7ddfba906797ad8cb42489e070Al Viro				(unsigned long)compat_ptr(arg));
70545048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	case BLKPG:
70656b26add02b4bdea81d5e0ebda60db1fe3311ad4Al Viro		return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
707f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKRAGET:
708f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKFRAGET:
709f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		if (!arg)
710f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann			return -EINVAL;
711f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		bdi = blk_get_backing_dev_info(bdev);
712f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		return compat_put_long(arg,
713f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann				       (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
714f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKROGET: /* compatible */
715f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		return compat_put_int(arg, bdev_read_only(bdev) != 0);
716f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
717f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		return compat_put_int(arg, block_size(bdev));
718f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKSSZGET: /* get block device hardware sector size */
719e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1Martin K. Petersen		return compat_put_int(arg, bdev_logical_block_size(bdev));
720f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKSECTGET:
72163f264965947ac6299452711f614f086955b2515Akinobu Mita		max_sectors = min_t(unsigned int, USHRT_MAX,
72263f264965947ac6299452711f614f086955b2515Akinobu Mita				    queue_max_sectors(bdev_get_queue(bdev)));
72363f264965947ac6299452711f614f086955b2515Akinobu Mita		return compat_put_ushort(arg, max_sectors);
724ef00f59c95fe6e002e7c6e3663cdea65e253f4ccMartin K. Petersen	case BLKROTATIONAL:
725ef00f59c95fe6e002e7c6e3663cdea65e253f4ccMartin K. Petersen		return compat_put_ushort(arg,
726ef00f59c95fe6e002e7c6e3663cdea65e253f4ccMartin K. Petersen					 !blk_queue_nonrot(bdev_get_queue(bdev)));
727f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKRASET: /* compatible, but no compat_ptr (!) */
728f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKFRASET:
729f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		if (!capable(CAP_SYS_ADMIN))
730f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann			return -EACCES;
731f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		bdi = blk_get_backing_dev_info(bdev);
732f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
733f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann		return 0;
734f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKGETSIZE:
73577304d2abac6101f7249754ffdd4421258877ab0Mike Snitzer		size = i_size_read(bdev->bd_inode);
73645048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		if ((size >> 9) > ~0UL)
737f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann			return -EFBIG;
73845048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		return compat_put_ulong(arg, size >> 9);
739f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann
740f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann	case BLKGETSIZE64_32:
74177304d2abac6101f7249754ffdd4421258877ab0Mike Snitzer		return compat_put_u64(arg, i_size_read(bdev->bd_inode));
742171044d449611c6e5040b37210ff6aba47f33ee4Arnd Bergmann
743171044d449611c6e5040b37210ff6aba47f33ee4Arnd Bergmann	case BLKTRACESETUP32:
744171044d449611c6e5040b37210ff6aba47f33ee4Arnd Bergmann	case BLKTRACESTART: /* compatible */
745171044d449611c6e5040b37210ff6aba47f33ee4Arnd Bergmann	case BLKTRACESTOP:  /* compatible */
746171044d449611c6e5040b37210ff6aba47f33ee4Arnd Bergmann	case BLKTRACETEARDOWN: /* compatible */
74745048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
7487199d4cdd8485f802df3e1bc131245c69009b9a4Arnd Bergmann		return ret;
74945048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	default:
75045048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		if (disk->fops->compat_ioctl)
75145048d0961cdbf7ddfba906797ad8cb42489e070Al Viro			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
75245048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		if (ret == -ENOIOCTLCMD)
75345048d0961cdbf7ddfba906797ad8cb42489e070Al Viro			ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
75445048d0961cdbf7ddfba906797ad8cb42489e070Al Viro		return ret;
75545048d0961cdbf7ddfba906797ad8cb42489e070Al Viro	}
756f58c4c0a17e500e767473598b3deafaa1d64051dArnd Bergmann}
757