linux/drivers/ide/ide-floppy_ioctl.c
<<
>>
Prefs
   1/*
   2 * ide-floppy IOCTLs handling.
   3 */
   4
   5#include <linux/kernel.h>
   6#include <linux/ide.h>
   7#include <linux/cdrom.h>
   8
   9#include <asm/unaligned.h>
  10
  11#include <scsi/scsi_ioctl.h>
  12
  13#include "ide-floppy.h"
  14
  15/*
  16 * Obtain the list of formattable capacities.
  17 * Very similar to ide_floppy_get_capacity, except that we push the capacity
  18 * descriptors to userland, instead of our own structures.
  19 *
  20 * Userland gives us the following structure:
  21 *
  22 * struct idefloppy_format_capacities {
  23 *      int nformats;
  24 *      struct {
  25 *              int nblocks;
  26 *              int blocksize;
  27 *      } formats[];
  28 * };
  29 *
  30 * userland initializes nformats to the number of allocated formats[] records.
  31 * On exit we set nformats to the number of records we've actually initialized.
  32 */
  33
  34static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
  35{
  36        struct ide_disk_obj *floppy = drive->driver_data;
  37        struct ide_atapi_pc pc;
  38        u8 header_len, desc_cnt;
  39        int i, blocks, length, u_array_size, u_index;
  40        int __user *argp;
  41
  42        if (get_user(u_array_size, arg))
  43                return -EFAULT;
  44
  45        if (u_array_size <= 0)
  46                return -EINVAL;
  47
  48        ide_floppy_create_read_capacity_cmd(&pc);
  49        if (ide_queue_pc_tail(drive, floppy->disk, &pc)) {
  50                printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
  51                return -EIO;
  52        }
  53
  54        header_len = pc.buf[3];
  55        desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
  56
  57        u_index = 0;
  58        argp = arg + 1;
  59
  60        /*
  61         * We always skip the first capacity descriptor.  That's the current
  62         * capacity.  We are interested in the remaining descriptors, the
  63         * formattable capacities.
  64         */
  65        for (i = 1; i < desc_cnt; i++) {
  66                unsigned int desc_start = 4 + i*8;
  67
  68                if (u_index >= u_array_size)
  69                        break;  /* User-supplied buffer too small */
  70
  71                blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
  72                length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
  73
  74                if (put_user(blocks, argp))
  75                        return -EFAULT;
  76
  77                ++argp;
  78
  79                if (put_user(length, argp))
  80                        return -EFAULT;
  81
  82                ++argp;
  83
  84                ++u_index;
  85        }
  86
  87        if (put_user(u_index, arg))
  88                return -EFAULT;
  89
  90        return 0;
  91}
  92
  93static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
  94                int l, int flags)
  95{
  96        ide_init_pc(pc);
  97        pc->c[0] = GPCMD_FORMAT_UNIT;
  98        pc->c[1] = 0x17;
  99
 100        memset(pc->buf, 0, 12);
 101        pc->buf[1] = 0xA2;
 102        /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
 103
 104        if (flags & 1)                          /* Verify bit on... */
 105                pc->buf[1] ^= 0x20;             /* ... turn off DCRT bit */
 106        pc->buf[3] = 8;
 107
 108        put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
 109        put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
 110        pc->buf_size = 12;
 111        pc->flags |= PC_FLAG_WRITING;
 112}
 113
 114static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
 115{
 116        struct ide_disk_obj *floppy = drive->driver_data;
 117        struct ide_atapi_pc pc;
 118
 119        drive->atapi_flags &= ~IDE_AFLAG_SRFP;
 120
 121        ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE);
 122        pc.flags |= PC_FLAG_SUPPRESS_ERROR;
 123
 124        if (ide_queue_pc_tail(drive, floppy->disk, &pc))
 125                return 1;
 126
 127        if (pc.buf[8 + 2] & 0x40)
 128                drive->atapi_flags |= IDE_AFLAG_SRFP;
 129
 130        return 0;
 131}
 132
 133static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
 134{
 135        struct ide_disk_obj *floppy = drive->driver_data;
 136        struct ide_atapi_pc pc;
 137        int blocks, length, flags, err = 0;
 138
 139        if (floppy->openers > 1) {
 140                /* Don't format if someone is using the disk */
 141                drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
 142                return -EBUSY;
 143        }
 144
 145        drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
 146
 147        /*
 148         * Send ATAPI_FORMAT_UNIT to the drive.
 149         *
 150         * Userland gives us the following structure:
 151         *
 152         * struct idefloppy_format_command {
 153         *        int nblocks;
 154         *        int blocksize;
 155         *        int flags;
 156         *        } ;
 157         *
 158         * flags is a bitmask, currently, the only defined flag is:
 159         *
 160         *        0x01 - verify media after format.
 161         */
 162        if (get_user(blocks, arg) ||
 163                        get_user(length, arg+1) ||
 164                        get_user(flags, arg+2)) {
 165                err = -EFAULT;
 166                goto out;
 167        }
 168
 169        (void)ide_floppy_get_sfrp_bit(drive);
 170        ide_floppy_create_format_unit_cmd(&pc, blocks, length, flags);
 171
 172        if (ide_queue_pc_tail(drive, floppy->disk, &pc))
 173                err = -EIO;
 174
 175out:
 176        if (err)
 177                drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
 178        return err;
 179}
 180
 181/*
 182 * Get ATAPI_FORMAT_UNIT progress indication.
 183 *
 184 * Userland gives a pointer to an int.  The int is set to a progress
 185 * indicator 0-65536, with 65536=100%.
 186 *
 187 * If the drive does not support format progress indication, we just check
 188 * the dsc bit, and return either 0 or 65536.
 189 */
 190
 191static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
 192{
 193        struct ide_disk_obj *floppy = drive->driver_data;
 194        struct ide_atapi_pc pc;
 195        int progress_indication = 0x10000;
 196
 197        if (drive->atapi_flags & IDE_AFLAG_SRFP) {
 198                ide_create_request_sense_cmd(drive, &pc);
 199                if (ide_queue_pc_tail(drive, floppy->disk, &pc))
 200                        return -EIO;
 201
 202                if (floppy->sense_key == 2 &&
 203                    floppy->asc == 4 &&
 204                    floppy->ascq == 4)
 205                        progress_indication = floppy->progress_indication;
 206
 207                /* Else assume format_unit has finished, and we're at 0x10000 */
 208        } else {
 209                ide_hwif_t *hwif = drive->hwif;
 210                unsigned long flags;
 211                u8 stat;
 212
 213                local_irq_save(flags);
 214                stat = hwif->tp_ops->read_status(hwif);
 215                local_irq_restore(flags);
 216
 217                progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
 218        }
 219
 220        if (put_user(progress_indication, arg))
 221                return -EFAULT;
 222
 223        return 0;
 224}
 225
 226static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
 227                               unsigned long arg, unsigned int cmd)
 228{
 229        struct ide_disk_obj *floppy = drive->driver_data;
 230        struct gendisk *disk = floppy->disk;
 231        int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
 232
 233        if (floppy->openers > 1)
 234                return -EBUSY;
 235
 236        ide_set_media_lock(drive, disk, prevent);
 237
 238        if (cmd == CDROMEJECT)
 239                ide_do_start_stop(drive, disk, 2);
 240
 241        return 0;
 242}
 243
 244static int ide_floppy_format_ioctl(ide_drive_t *drive, fmode_t mode,
 245                                   unsigned int cmd, void __user *argp)
 246{
 247        switch (cmd) {
 248        case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
 249                return 0;
 250        case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
 251                return ide_floppy_get_format_capacities(drive, argp);
 252        case IDEFLOPPY_IOCTL_FORMAT_START:
 253                if (!(mode & FMODE_WRITE))
 254                        return -EPERM;
 255                return ide_floppy_format_unit(drive, (int __user *)argp);
 256        case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
 257                return ide_floppy_get_format_progress(drive, argp);
 258        default:
 259                return -ENOTTY;
 260        }
 261}
 262
 263int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
 264                     fmode_t mode, unsigned int cmd, unsigned long arg)
 265{
 266        struct ide_atapi_pc pc;
 267        void __user *argp = (void __user *)arg;
 268        int err;
 269
 270        if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
 271                return ide_floppy_lockdoor(drive, &pc, arg, cmd);
 272
 273        err = ide_floppy_format_ioctl(drive, mode, cmd, argp);
 274        if (err != -ENOTTY)
 275                return err;
 276
 277        /*
 278         * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
 279         * and CDROM_SEND_PACKET (legacy) ioctls
 280         */
 281        if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
 282                err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk,
 283                                mode, cmd, argp);
 284
 285        if (err == -ENOTTY)
 286                err = generic_ide_ioctl(drive, bdev, cmd, arg);
 287
 288        return err;
 289}
 290