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