Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.9-rc4 306 lines 7.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * IDE ioctls handling. 4 */ 5 6#include <linux/compat.h> 7#include <linux/export.h> 8#include <linux/hdreg.h> 9#include <linux/ide.h> 10#include <linux/slab.h> 11 12static int put_user_long(long val, unsigned long arg) 13{ 14 if (in_compat_syscall()) 15 return put_user(val, (compat_long_t __user *)compat_ptr(arg)); 16 17 return put_user(val, (long __user *)arg); 18} 19 20static const struct ide_ioctl_devset ide_ioctl_settings[] = { 21{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit }, 22{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings }, 23{ HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq }, 24{ HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma }, 25{ -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode }, 26{ 0 } 27}; 28 29int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev, 30 unsigned int cmd, unsigned long arg, 31 const struct ide_ioctl_devset *s) 32{ 33 const struct ide_devset *ds; 34 int err = -EOPNOTSUPP; 35 36 for (; (ds = s->setting); s++) { 37 if (ds->get && s->get_ioctl == cmd) 38 goto read_val; 39 else if (ds->set && s->set_ioctl == cmd) 40 goto set_val; 41 } 42 43 return err; 44 45read_val: 46 mutex_lock(&ide_setting_mtx); 47 err = ds->get(drive); 48 mutex_unlock(&ide_setting_mtx); 49 return err >= 0 ? put_user_long(err, arg) : err; 50 51set_val: 52 if (bdev != bdev->bd_contains) 53 err = -EINVAL; 54 else { 55 if (!capable(CAP_SYS_ADMIN)) 56 err = -EACCES; 57 else { 58 mutex_lock(&ide_setting_mtx); 59 err = ide_devset_execute(drive, ds, arg); 60 mutex_unlock(&ide_setting_mtx); 61 } 62 } 63 return err; 64} 65EXPORT_SYMBOL_GPL(ide_setting_ioctl); 66 67static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, 68 void __user *argp) 69{ 70 u16 *id = NULL; 71 int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142; 72 int rc = 0; 73 74 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { 75 rc = -ENOMSG; 76 goto out; 77 } 78 79 /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */ 80 id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL); 81 if (id == NULL) { 82 rc = -ENOMEM; 83 goto out; 84 } 85 86 memcpy(id, drive->id, size); 87 ata_id_to_hd_driveid(id); 88 89 if (copy_to_user(argp, id, size)) 90 rc = -EFAULT; 91 92 kfree(id); 93out: 94 return rc; 95} 96 97static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg) 98{ 99 return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) 100 << IDE_NICE_DSC_OVERLAP) | 101 (!!(drive->dev_flags & IDE_DFLAG_NICE1) 102 << IDE_NICE_1), arg); 103} 104 105static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg) 106{ 107 if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) 108 return -EPERM; 109 110 if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) && 111 (drive->media != ide_tape)) 112 return -EPERM; 113 114 if ((arg >> IDE_NICE_DSC_OVERLAP) & 1) 115 drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; 116 else 117 drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; 118 119 if ((arg >> IDE_NICE_1) & 1) 120 drive->dev_flags |= IDE_DFLAG_NICE1; 121 else 122 drive->dev_flags &= ~IDE_DFLAG_NICE1; 123 124 return 0; 125} 126 127static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp) 128{ 129 u8 *buf = NULL; 130 int bufsize = 0, err = 0; 131 u8 args[4], xfer_rate = 0; 132 struct ide_cmd cmd; 133 struct ide_taskfile *tf = &cmd.tf; 134 135 if (NULL == argp) { 136 struct request *rq; 137 138 rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); 139 ide_req(rq)->type = ATA_PRIV_TASKFILE; 140 blk_execute_rq(drive->queue, NULL, rq, 0); 141 err = scsi_req(rq)->result ? -EIO : 0; 142 blk_put_request(rq); 143 144 return err; 145 } 146 147 if (copy_from_user(args, argp, 4)) 148 return -EFAULT; 149 150 memset(&cmd, 0, sizeof(cmd)); 151 tf->feature = args[2]; 152 if (args[0] == ATA_CMD_SMART) { 153 tf->nsect = args[3]; 154 tf->lbal = args[1]; 155 tf->lbam = ATA_SMART_LBAM_PASS; 156 tf->lbah = ATA_SMART_LBAH_PASS; 157 cmd.valid.out.tf = IDE_VALID_OUT_TF; 158 cmd.valid.in.tf = IDE_VALID_NSECT; 159 } else { 160 tf->nsect = args[1]; 161 cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; 162 cmd.valid.in.tf = IDE_VALID_NSECT; 163 } 164 tf->command = args[0]; 165 cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA; 166 167 if (args[3]) { 168 cmd.tf_flags |= IDE_TFLAG_IO_16BIT; 169 bufsize = SECTOR_SIZE * args[3]; 170 buf = kzalloc(bufsize, GFP_KERNEL); 171 if (buf == NULL) 172 return -ENOMEM; 173 } 174 175 if (tf->command == ATA_CMD_SET_FEATURES && 176 tf->feature == SETFEATURES_XFER && 177 tf->nsect >= XFER_SW_DMA_0) { 178 xfer_rate = ide_find_dma_mode(drive, tf->nsect); 179 if (xfer_rate != tf->nsect) { 180 err = -EINVAL; 181 goto abort; 182 } 183 184 cmd.tf_flags |= IDE_TFLAG_SET_XFER; 185 } 186 187 err = ide_raw_taskfile(drive, &cmd, buf, args[3]); 188 189 args[0] = tf->status; 190 args[1] = tf->error; 191 args[2] = tf->nsect; 192abort: 193 if (copy_to_user(argp, &args, 4)) 194 err = -EFAULT; 195 if (buf) { 196 if (copy_to_user((argp + 4), buf, bufsize)) 197 err = -EFAULT; 198 kfree(buf); 199 } 200 return err; 201} 202 203static int ide_task_ioctl(ide_drive_t *drive, void __user *p) 204{ 205 int err = 0; 206 u8 args[7]; 207 struct ide_cmd cmd; 208 209 if (copy_from_user(args, p, 7)) 210 return -EFAULT; 211 212 memset(&cmd, 0, sizeof(cmd)); 213 memcpy(&cmd.tf.feature, &args[1], 6); 214 cmd.tf.command = args[0]; 215 cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 216 cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 217 218 err = ide_no_data_taskfile(drive, &cmd); 219 220 args[0] = cmd.tf.command; 221 memcpy(&args[1], &cmd.tf.feature, 6); 222 223 if (copy_to_user(p, args, 7)) 224 err = -EFAULT; 225 226 return err; 227} 228 229static int generic_drive_reset(ide_drive_t *drive) 230{ 231 struct request *rq; 232 int ret = 0; 233 234 rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); 235 ide_req(rq)->type = ATA_PRIV_MISC; 236 scsi_req(rq)->cmd_len = 1; 237 scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET; 238 blk_execute_rq(drive->queue, NULL, rq, 1); 239 ret = scsi_req(rq)->result; 240 blk_put_request(rq); 241 return ret; 242} 243 244int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, 245 unsigned int cmd, unsigned long arg) 246{ 247 int err; 248 void __user *argp = (void __user *)arg; 249 250 if (in_compat_syscall()) 251 argp = compat_ptr(arg); 252 253 err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings); 254 if (err != -EOPNOTSUPP) 255 return err; 256 257 switch (cmd) { 258 case HDIO_OBSOLETE_IDENTITY: 259 case HDIO_GET_IDENTITY: 260 if (bdev != bdev->bd_contains) 261 return -EINVAL; 262 return ide_get_identity_ioctl(drive, cmd, argp); 263 case HDIO_GET_NICE: 264 return ide_get_nice_ioctl(drive, arg); 265 case HDIO_SET_NICE: 266 if (!capable(CAP_SYS_ADMIN)) 267 return -EACCES; 268 return ide_set_nice_ioctl(drive, arg); 269#ifdef CONFIG_IDE_TASK_IOCTL 270 case HDIO_DRIVE_TASKFILE: 271 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 272 return -EACCES; 273 /* missing compat handler for HDIO_DRIVE_TASKFILE */ 274 if (in_compat_syscall()) 275 return -ENOTTY; 276 if (drive->media == ide_disk) 277 return ide_taskfile_ioctl(drive, arg); 278 return -ENOMSG; 279#endif 280 case HDIO_DRIVE_CMD: 281 if (!capable(CAP_SYS_RAWIO)) 282 return -EACCES; 283 return ide_cmd_ioctl(drive, argp); 284 case HDIO_DRIVE_TASK: 285 if (!capable(CAP_SYS_RAWIO)) 286 return -EACCES; 287 return ide_task_ioctl(drive, argp); 288 case HDIO_DRIVE_RESET: 289 if (!capable(CAP_SYS_ADMIN)) 290 return -EACCES; 291 return generic_drive_reset(drive); 292 case HDIO_GET_BUSSTATE: 293 if (!capable(CAP_SYS_ADMIN)) 294 return -EACCES; 295 if (put_user_long(BUSSTATE_ON, arg)) 296 return -EFAULT; 297 return 0; 298 case HDIO_SET_BUSSTATE: 299 if (!capable(CAP_SYS_ADMIN)) 300 return -EACCES; 301 return -EOPNOTSUPP; 302 default: 303 return -EINVAL; 304 } 305} 306EXPORT_SYMBOL(generic_ide_ioctl);