linux/drivers/ide/ide-taskfile.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/ide/ide-taskfile.c     Version 0.38    March 05, 2003
   3 *
   4 *  Copyright (C) 2000-2002     Michael Cornwell <cornwell@acm.org>
   5 *  Copyright (C) 2000-2002     Andre Hedrick <andre@linux-ide.org>
   6 *  Copyright (C) 2001-2002     Klaus Smolin
   7 *                                      IBM Storage Technology Division
   8 *  Copyright (C) 2003-2004     Bartlomiej Zolnierkiewicz
   9 *
  10 *  The big the bad and the ugly.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/types.h>
  15#include <linux/string.h>
  16#include <linux/kernel.h>
  17#include <linux/timer.h>
  18#include <linux/mm.h>
  19#include <linux/sched.h>
  20#include <linux/interrupt.h>
  21#include <linux/major.h>
  22#include <linux/errno.h>
  23#include <linux/genhd.h>
  24#include <linux/blkpg.h>
  25#include <linux/slab.h>
  26#include <linux/pci.h>
  27#include <linux/delay.h>
  28#include <linux/hdreg.h>
  29#include <linux/ide.h>
  30#include <linux/bitops.h>
  31#include <linux/scatterlist.h>
  32
  33#include <asm/byteorder.h>
  34#include <asm/irq.h>
  35#include <asm/uaccess.h>
  36#include <asm/io.h>
  37
  38static void ata_bswap_data (void *buffer, int wcount)
  39{
  40        u16 *p = buffer;
  41
  42        while (wcount--) {
  43                *p = *p << 8 | *p >> 8; p++;
  44                *p = *p << 8 | *p >> 8; p++;
  45        }
  46}
  47
  48static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
  49{
  50        HWIF(drive)->ata_input_data(drive, buffer, wcount);
  51        if (drive->bswap)
  52                ata_bswap_data(buffer, wcount);
  53}
  54
  55static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
  56{
  57        if (drive->bswap) {
  58                ata_bswap_data(buffer, wcount);
  59                HWIF(drive)->ata_output_data(drive, buffer, wcount);
  60                ata_bswap_data(buffer, wcount);
  61        } else {
  62                HWIF(drive)->ata_output_data(drive, buffer, wcount);
  63        }
  64}
  65
  66int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
  67{
  68        ide_task_t args;
  69        memset(&args, 0, sizeof(ide_task_t));
  70        args.tfRegister[IDE_NSECTOR_OFFSET]     = 0x01;
  71        if (drive->media == ide_disk)
  72                args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_IDENTIFY;
  73        else
  74                args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_PIDENTIFY;
  75        args.command_type = IDE_DRIVE_TASK_IN;
  76        args.data_phase   = TASKFILE_IN;
  77        args.handler      = &task_in_intr;
  78        return ide_raw_taskfile(drive, &args, buf);
  79}
  80
  81ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
  82{
  83        ide_hwif_t *hwif        = HWIF(drive);
  84        task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
  85        hob_struct_t *hobfile   = (hob_struct_t *) task->hobRegister;
  86        u8 HIHI                 = (drive->addressing == 1) ? 0xE0 : 0xEF;
  87
  88        /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
  89        if (IDE_CONTROL_REG) {
  90                /* clear nIEN */
  91                hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
  92        }
  93        SELECT_MASK(drive, 0);
  94
  95        if (drive->addressing == 1) {
  96                hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
  97                hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
  98                hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
  99                hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
 100                hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
 101        }
 102
 103        hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
 104        hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
 105        hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
 106        hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
 107        hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 108
 109        hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 110
 111        if (task->handler != NULL) {
 112                if (task->prehandler != NULL) {
 113                        hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
 114                        ndelay(400);    /* FIXME */
 115                        return task->prehandler(drive, task->rq);
 116                }
 117                ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
 118                return ide_started;
 119        }
 120
 121        if (!drive->using_dma)
 122                return ide_stopped;
 123
 124        switch (taskfile->command) {
 125                case WIN_WRITEDMA_ONCE:
 126                case WIN_WRITEDMA:
 127                case WIN_WRITEDMA_EXT:
 128                case WIN_READDMA_ONCE:
 129                case WIN_READDMA:
 130                case WIN_READDMA_EXT:
 131                case WIN_IDENTIFY_DMA:
 132                        if (!hwif->dma_setup(drive)) {
 133                                hwif->dma_exec_cmd(drive, taskfile->command);
 134                                hwif->dma_start(drive);
 135                                return ide_started;
 136                        }
 137                        break;
 138                default:
 139                        if (task->handler == NULL)
 140                                return ide_stopped;
 141        }
 142
 143        return ide_stopped;
 144}
 145
 146/*
 147 * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
 148 */
 149ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 150{
 151        ide_hwif_t *hwif = HWIF(drive);
 152        u8 stat;
 153
 154        if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 155                drive->mult_count = drive->mult_req;
 156        } else {
 157                drive->mult_req = drive->mult_count = 0;
 158                drive->special.b.recalibrate = 1;
 159                (void) ide_dump_status(drive, "set_multmode", stat);
 160        }
 161        return ide_stopped;
 162}
 163
 164/*
 165 * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
 166 */
 167ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 168{
 169        ide_hwif_t *hwif = HWIF(drive);
 170        int retries = 5;
 171        u8 stat;
 172
 173        while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
 174                udelay(10);
 175
 176        if (OK_STAT(stat, READY_STAT, BAD_STAT))
 177                return ide_stopped;
 178
 179        if (stat & (ERR_STAT|DRQ_STAT))
 180                return ide_error(drive, "set_geometry_intr", stat);
 181
 182        BUG_ON(HWGROUP(drive)->handler != NULL);
 183        ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
 184        return ide_started;
 185}
 186
 187/*
 188 * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
 189 */
 190ide_startstop_t recal_intr (ide_drive_t *drive)
 191{
 192        ide_hwif_t *hwif = HWIF(drive);
 193        u8 stat;
 194
 195        if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
 196                return ide_error(drive, "recal_intr", stat);
 197        return ide_stopped;
 198}
 199
 200/*
 201 * Handler for commands without a data phase
 202 */
 203ide_startstop_t task_no_data_intr (ide_drive_t *drive)
 204{
 205        ide_task_t *args        = HWGROUP(drive)->rq->special;
 206        ide_hwif_t *hwif        = HWIF(drive);
 207        u8 stat;
 208
 209        local_irq_enable_in_hardirq();
 210        if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 211                return ide_error(drive, "task_no_data_intr", stat);
 212                /* calls ide_end_drive_cmd */
 213        }
 214        if (args)
 215                ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 216
 217        return ide_stopped;
 218}
 219
 220EXPORT_SYMBOL(task_no_data_intr);
 221
 222static u8 wait_drive_not_busy(ide_drive_t *drive)
 223{
 224        ide_hwif_t *hwif = HWIF(drive);
 225        int retries;
 226        u8 stat;
 227
 228        /*
 229         * Last sector was transfered, wait until drive is ready.
 230         * This can take up to 10 usec, but we will wait max 1 ms
 231         * (drive_cmd_intr() waits that long).
 232         */
 233        for (retries = 0; retries < 100; retries++) {
 234                if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
 235                        udelay(10);
 236                else
 237                        break;
 238        }
 239
 240        if (stat & BUSY_STAT)
 241                printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
 242
 243        return stat;
 244}
 245
 246static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
 247{
 248        ide_hwif_t *hwif = drive->hwif;
 249        struct scatterlist *sg = hwif->sg_table;
 250        struct scatterlist *cursg = hwif->cursg;
 251        struct page *page;
 252#ifdef CONFIG_HIGHMEM
 253        unsigned long flags;
 254#endif
 255        unsigned int offset;
 256        u8 *buf;
 257
 258        cursg = hwif->cursg;
 259        if (!cursg) {
 260                cursg = sg;
 261                hwif->cursg = sg;
 262        }
 263
 264        page = sg_page(cursg);
 265        offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
 266
 267        /* get the current page and offset */
 268        page = nth_page(page, (offset >> PAGE_SHIFT));
 269        offset %= PAGE_SIZE;
 270
 271#ifdef CONFIG_HIGHMEM
 272        local_irq_save(flags);
 273#endif
 274        buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
 275
 276        hwif->nleft--;
 277        hwif->cursg_ofs++;
 278
 279        if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) {
 280                hwif->cursg = sg_next(hwif->cursg);
 281                hwif->cursg_ofs = 0;
 282        }
 283
 284        /* do the actual data transfer */
 285        if (write)
 286                taskfile_output_data(drive, buf, SECTOR_WORDS);
 287        else
 288                taskfile_input_data(drive, buf, SECTOR_WORDS);
 289
 290        kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 291#ifdef CONFIG_HIGHMEM
 292        local_irq_restore(flags);
 293#endif
 294}
 295
 296static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
 297{
 298        unsigned int nsect;
 299
 300        nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
 301        while (nsect--)
 302                ide_pio_sector(drive, write);
 303}
 304
 305static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 306                                     unsigned int write)
 307{
 308        if (rq->bio)    /* fs request */
 309                rq->errors = 0;
 310
 311        touch_softlockup_watchdog();
 312
 313        switch (drive->hwif->data_phase) {
 314        case TASKFILE_MULTI_IN:
 315        case TASKFILE_MULTI_OUT:
 316                ide_pio_multi(drive, write);
 317                break;
 318        default:
 319                ide_pio_sector(drive, write);
 320                break;
 321        }
 322}
 323
 324static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
 325                                  const char *s, u8 stat)
 326{
 327        if (rq->bio) {
 328                ide_hwif_t *hwif = drive->hwif;
 329                int sectors = hwif->nsect - hwif->nleft;
 330
 331                switch (hwif->data_phase) {
 332                case TASKFILE_IN:
 333                        if (hwif->nleft)
 334                                break;
 335                        /* fall through */
 336                case TASKFILE_OUT:
 337                        sectors--;
 338                        break;
 339                case TASKFILE_MULTI_IN:
 340                        if (hwif->nleft)
 341                                break;
 342                        /* fall through */
 343                case TASKFILE_MULTI_OUT:
 344                        sectors -= drive->mult_count;
 345                default:
 346                        break;
 347                }
 348
 349                if (sectors > 0) {
 350                        ide_driver_t *drv;
 351
 352                        drv = *(ide_driver_t **)rq->rq_disk->private_data;
 353                        drv->end_request(drive, 1, sectors);
 354                }
 355        }
 356        return ide_error(drive, s, stat);
 357}
 358
 359static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 360{
 361        HWIF(drive)->cursg = NULL;
 362
 363        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
 364                ide_task_t *task = rq->special;
 365
 366                if (task->tf_out_flags.all) {
 367                        u8 err = drive->hwif->INB(IDE_ERROR_REG);
 368                        ide_end_drive_cmd(drive, stat, err);
 369                        return;
 370                }
 371        }
 372
 373        if (rq->rq_disk) {
 374                ide_driver_t *drv;
 375
 376                drv = *(ide_driver_t **)rq->rq_disk->private_data;;
 377                drv->end_request(drive, 1, rq->hard_nr_sectors);
 378        } else
 379                ide_end_request(drive, 1, rq->hard_nr_sectors);
 380}
 381
 382/*
 383 * Handler for command with PIO data-in phase (Read/Read Multiple).
 384 */
 385ide_startstop_t task_in_intr (ide_drive_t *drive)
 386{
 387        ide_hwif_t *hwif = drive->hwif;
 388        struct request *rq = HWGROUP(drive)->rq;
 389        u8 stat = hwif->INB(IDE_STATUS_REG);
 390
 391        /* new way for dealing with premature shared PCI interrupts */
 392        if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
 393                if (stat & (ERR_STAT | DRQ_STAT))
 394                        return task_error(drive, rq, __FUNCTION__, stat);
 395                /* No data yet, so wait for another IRQ. */
 396                ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 397                return ide_started;
 398        }
 399
 400        ide_pio_datablock(drive, rq, 0);
 401
 402        /* If it was the last datablock check status and finish transfer. */
 403        if (!hwif->nleft) {
 404                stat = wait_drive_not_busy(drive);
 405                if (!OK_STAT(stat, 0, BAD_R_STAT))
 406                        return task_error(drive, rq, __FUNCTION__, stat);
 407                task_end_request(drive, rq, stat);
 408                return ide_stopped;
 409        }
 410
 411        /* Still data left to transfer. */
 412        ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 413
 414        return ide_started;
 415}
 416EXPORT_SYMBOL(task_in_intr);
 417
 418/*
 419 * Handler for command with PIO data-out phase (Write/Write Multiple).
 420 */
 421static ide_startstop_t task_out_intr (ide_drive_t *drive)
 422{
 423        ide_hwif_t *hwif = drive->hwif;
 424        struct request *rq = HWGROUP(drive)->rq;
 425        u8 stat = hwif->INB(IDE_STATUS_REG);
 426
 427        if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
 428                return task_error(drive, rq, __FUNCTION__, stat);
 429
 430        /* Deal with unexpected ATA data phase. */
 431        if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
 432                return task_error(drive, rq, __FUNCTION__, stat);
 433
 434        if (!hwif->nleft) {
 435                task_end_request(drive, rq, stat);
 436                return ide_stopped;
 437        }
 438
 439        /* Still data left to transfer. */
 440        ide_pio_datablock(drive, rq, 1);
 441        ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
 442
 443        return ide_started;
 444}
 445
 446ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 447{
 448        ide_startstop_t startstop;
 449
 450        if (ide_wait_stat(&startstop, drive, DATA_READY,
 451                          drive->bad_wstat, WAIT_DRQ)) {
 452                printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
 453                                drive->name,
 454                                drive->hwif->data_phase ? "MULT" : "",
 455                                drive->addressing ? "_EXT" : "");
 456                return startstop;
 457        }
 458
 459        if (!drive->unmask)
 460                local_irq_disable();
 461
 462        ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
 463        ide_pio_datablock(drive, rq, 1);
 464
 465        return ide_started;
 466}
 467EXPORT_SYMBOL(pre_task_out_intr);
 468
 469static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
 470{
 471        struct request rq;
 472
 473        memset(&rq, 0, sizeof(rq));
 474        rq.ref_count = 1;
 475        rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
 476        rq.buffer = buf;
 477
 478        /*
 479         * (ks) We transfer currently only whole sectors.
 480         * This is suffient for now.  But, it would be great,
 481         * if we would find a solution to transfer any size.
 482         * To support special commands like READ LONG.
 483         */
 484        if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
 485                if (data_size == 0)
 486                        rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
 487                else
 488                        rq.nr_sectors = data_size / SECTOR_SIZE;
 489
 490                if (!rq.nr_sectors) {
 491                        printk(KERN_ERR "%s: in/out command without data\n",
 492                                        drive->name);
 493                        return -EFAULT;
 494                }
 495
 496                rq.hard_nr_sectors = rq.nr_sectors;
 497                rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
 498
 499                if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
 500                        rq.cmd_flags |= REQ_RW;
 501        }
 502
 503        rq.special = args;
 504        args->rq = &rq;
 505        return ide_do_drive_cmd(drive, &rq, ide_wait);
 506}
 507
 508int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
 509{
 510        return ide_diag_taskfile(drive, args, 0, buf);
 511}
 512
 513EXPORT_SYMBOL(ide_raw_taskfile);
 514
 515#ifdef CONFIG_IDE_TASK_IOCTL
 516int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 517{
 518        ide_task_request_t      *req_task;
 519        ide_task_t              args;
 520        u8 *outbuf              = NULL;
 521        u8 *inbuf               = NULL;
 522        task_ioreg_t *argsptr   = args.tfRegister;
 523        task_ioreg_t *hobsptr   = args.hobRegister;
 524        int err                 = 0;
 525        int tasksize            = sizeof(struct ide_task_request_s);
 526        unsigned int taskin     = 0;
 527        unsigned int taskout    = 0;
 528        u8 io_32bit             = drive->io_32bit;
 529        char __user *buf = (char __user *)arg;
 530
 531//      printk("IDE Taskfile ...\n");
 532
 533        req_task = kzalloc(tasksize, GFP_KERNEL);
 534        if (req_task == NULL) return -ENOMEM;
 535        if (copy_from_user(req_task, buf, tasksize)) {
 536                kfree(req_task);
 537                return -EFAULT;
 538        }
 539
 540        taskout = req_task->out_size;
 541        taskin  = req_task->in_size;
 542        
 543        if (taskin > 65536 || taskout > 65536) {
 544                err = -EINVAL;
 545                goto abort;
 546        }
 547
 548        if (taskout) {
 549                int outtotal = tasksize;
 550                outbuf = kzalloc(taskout, GFP_KERNEL);
 551                if (outbuf == NULL) {
 552                        err = -ENOMEM;
 553                        goto abort;
 554                }
 555                if (copy_from_user(outbuf, buf + outtotal, taskout)) {
 556                        err = -EFAULT;
 557                        goto abort;
 558                }
 559        }
 560
 561        if (taskin) {
 562                int intotal = tasksize + taskout;
 563                inbuf = kzalloc(taskin, GFP_KERNEL);
 564                if (inbuf == NULL) {
 565                        err = -ENOMEM;
 566                        goto abort;
 567                }
 568                if (copy_from_user(inbuf, buf + intotal, taskin)) {
 569                        err = -EFAULT;
 570                        goto abort;
 571                }
 572        }
 573
 574        memset(&args, 0, sizeof(ide_task_t));
 575        memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
 576        memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 577
 578        args.tf_in_flags  = req_task->in_flags;
 579        args.tf_out_flags = req_task->out_flags;
 580        args.data_phase   = req_task->data_phase;
 581        args.command_type = req_task->req_cmd;
 582
 583        drive->io_32bit = 0;
 584        switch(req_task->data_phase) {
 585                case TASKFILE_OUT_DMAQ:
 586                case TASKFILE_OUT_DMA:
 587                        err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 588                        break;
 589                case TASKFILE_IN_DMAQ:
 590                case TASKFILE_IN_DMA:
 591                        err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 592                        break;
 593                case TASKFILE_MULTI_OUT:
 594                        if (!drive->mult_count) {
 595                                /* (hs): give up if multcount is not set */
 596                                printk(KERN_ERR "%s: %s Multimode Write " \
 597                                        "multcount is not set\n",
 598                                        drive->name, __FUNCTION__);
 599                                err = -EPERM;
 600                                goto abort;
 601                        }
 602                        /* fall through */
 603                case TASKFILE_OUT:
 604                        args.prehandler = &pre_task_out_intr;
 605                        args.handler = &task_out_intr;
 606                        err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 607                        break;
 608                case TASKFILE_MULTI_IN:
 609                        if (!drive->mult_count) {
 610                                /* (hs): give up if multcount is not set */
 611                                printk(KERN_ERR "%s: %s Multimode Read failure " \
 612                                        "multcount is not set\n",
 613                                        drive->name, __FUNCTION__);
 614                                err = -EPERM;
 615                                goto abort;
 616                        }
 617                        /* fall through */
 618                case TASKFILE_IN:
 619                        args.handler = &task_in_intr;
 620                        err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 621                        break;
 622                case TASKFILE_NO_DATA:
 623                        args.handler = &task_no_data_intr;
 624                        err = ide_diag_taskfile(drive, &args, 0, NULL);
 625                        break;
 626                default:
 627                        err = -EFAULT;
 628                        goto abort;
 629        }
 630
 631        memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
 632        memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
 633        req_task->in_flags  = args.tf_in_flags;
 634        req_task->out_flags = args.tf_out_flags;
 635
 636        if (copy_to_user(buf, req_task, tasksize)) {
 637                err = -EFAULT;
 638                goto abort;
 639        }
 640        if (taskout) {
 641                int outtotal = tasksize;
 642                if (copy_to_user(buf + outtotal, outbuf, taskout)) {
 643                        err = -EFAULT;
 644                        goto abort;
 645                }
 646        }
 647        if (taskin) {
 648                int intotal = tasksize + taskout;
 649                if (copy_to_user(buf + intotal, inbuf, taskin)) {
 650                        err = -EFAULT;
 651                        goto abort;
 652                }
 653        }
 654abort:
 655        kfree(req_task);
 656        kfree(outbuf);
 657        kfree(inbuf);
 658
 659//      printk("IDE Taskfile ioctl ended. rc = %i\n", err);
 660
 661        drive->io_32bit = io_32bit;
 662
 663        return err;
 664}
 665#endif
 666
 667int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
 668{
 669        struct request rq;
 670        u8 buffer[4];
 671
 672        if (!buf)
 673                buf = buffer;
 674        memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
 675        ide_init_drive_cmd(&rq);
 676        rq.buffer = buf;
 677        *buf++ = cmd;
 678        *buf++ = nsect;
 679        *buf++ = feature;
 680        *buf++ = sectors;
 681        return ide_do_drive_cmd(drive, &rq, ide_wait);
 682}
 683
 684int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 685{
 686        int err = 0;
 687        u8 args[4], *argbuf = args;
 688        u8 xfer_rate = 0;
 689        int argsize = 4;
 690        ide_task_t tfargs;
 691
 692        if (NULL == (void *) arg) {
 693                struct request rq;
 694                ide_init_drive_cmd(&rq);
 695                return ide_do_drive_cmd(drive, &rq, ide_wait);
 696        }
 697
 698        if (copy_from_user(args, (void __user *)arg, 4))
 699                return -EFAULT;
 700
 701        memset(&tfargs, 0, sizeof(ide_task_t));
 702        tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
 703        tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
 704        tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
 705        tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
 706        tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
 707        tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
 708        tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
 709
 710        if (args[3]) {
 711                argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
 712                argbuf = kzalloc(argsize, GFP_KERNEL);
 713                if (argbuf == NULL)
 714                        return -ENOMEM;
 715        }
 716        if (set_transfer(drive, &tfargs)) {
 717                xfer_rate = args[1];
 718                if (ide_ata66_check(drive, &tfargs))
 719                        goto abort;
 720        }
 721
 722        err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
 723
 724        if (!err && xfer_rate) {
 725                /* active-retuning-calls future */
 726                ide_set_xfer_rate(drive, xfer_rate);
 727                ide_driveid_update(drive);
 728        }
 729abort:
 730        if (copy_to_user((void __user *)arg, argbuf, argsize))
 731                err = -EFAULT;
 732        if (argsize > 4)
 733                kfree(argbuf);
 734        return err;
 735}
 736
 737static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
 738{
 739        struct request rq;
 740
 741        ide_init_drive_cmd(&rq);
 742        rq.cmd_type = REQ_TYPE_ATA_TASK;
 743        rq.buffer = buf;
 744        return ide_do_drive_cmd(drive, &rq, ide_wait);
 745}
 746
 747int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 748{
 749        void __user *p = (void __user *)arg;
 750        int err = 0;
 751        u8 args[7], *argbuf = args;
 752        int argsize = 7;
 753
 754        if (copy_from_user(args, p, 7))
 755                return -EFAULT;
 756        err = ide_wait_cmd_task(drive, argbuf);
 757        if (copy_to_user(p, argbuf, argsize))
 758                err = -EFAULT;
 759        return err;
 760}
 761
 762/*
 763 * NOTICE: This is additions from IBM to provide a discrete interface,
 764 * for selective taskregister access operations.  Nice JOB Klaus!!!
 765 * Glad to be able to work and co-develop this with you and IBM.
 766 */
 767ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
 768{
 769        ide_hwif_t *hwif        = HWIF(drive);
 770        task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
 771        hob_struct_t *hobfile   = (hob_struct_t *) task->hobRegister;
 772
 773        if (task->data_phase == TASKFILE_MULTI_IN ||
 774            task->data_phase == TASKFILE_MULTI_OUT) {
 775                if (!drive->mult_count) {
 776                        printk(KERN_ERR "%s: multimode not set!\n", drive->name);
 777                        return ide_stopped;
 778                }
 779        }
 780
 781        /*
 782         * (ks) Check taskfile in flags.
 783         * If set, then execute as it is defined.
 784         * If not set, then define default settings.
 785         * The default values are:
 786         *      read all taskfile registers (except data)
 787         *      read the hob registers (sector, nsector, lcyl, hcyl)
 788         */
 789        if (task->tf_in_flags.all == 0) {
 790                task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
 791                if (drive->addressing == 1)
 792                        task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
 793        }
 794
 795        /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
 796        if (IDE_CONTROL_REG)
 797                /* clear nIEN */
 798                hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 799        SELECT_MASK(drive, 0);
 800
 801        if (task->tf_out_flags.b.data) {
 802                u16 data =  taskfile->data + (hobfile->data << 8);
 803                hwif->OUTW(data, IDE_DATA_REG);
 804        }
 805
 806        /* (ks) send hob registers first */
 807        if (task->tf_out_flags.b.nsector_hob)
 808                hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
 809        if (task->tf_out_flags.b.sector_hob)
 810                hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
 811        if (task->tf_out_flags.b.lcyl_hob)
 812                hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
 813        if (task->tf_out_flags.b.hcyl_hob)
 814                hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
 815
 816        /* (ks) Send now the standard registers */
 817        if (task->tf_out_flags.b.error_feature)
 818                hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
 819        /* refers to number of sectors to transfer */
 820        if (task->tf_out_flags.b.nsector)
 821                hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
 822        /* refers to sector offset or start sector */
 823        if (task->tf_out_flags.b.sector)
 824                hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
 825        if (task->tf_out_flags.b.lcyl)
 826                hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
 827        if (task->tf_out_flags.b.hcyl)
 828                hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 829
 830        /*
 831         * (ks) In the flagged taskfile approch, we will use all specified
 832         * registers and the register value will not be changed, except the
 833         * select bit (master/slave) in the drive_head register. We must make
 834         * sure that the desired drive is selected.
 835         */
 836        hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
 837        switch(task->data_phase) {
 838
 839                case TASKFILE_OUT_DMAQ:
 840                case TASKFILE_OUT_DMA:
 841                case TASKFILE_IN_DMAQ:
 842                case TASKFILE_IN_DMA:
 843                        if (!drive->using_dma)
 844                                break;
 845
 846                        if (!hwif->dma_setup(drive)) {
 847                                hwif->dma_exec_cmd(drive, taskfile->command);
 848                                hwif->dma_start(drive);
 849                                return ide_started;
 850                        }
 851                        break;
 852
 853                default:
 854                        if (task->handler == NULL)
 855                                return ide_stopped;
 856
 857                        /* Issue the command */
 858                        if (task->prehandler) {
 859                                hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
 860                                ndelay(400);    /* FIXME */
 861                                return task->prehandler(drive, task->rq);
 862                        }
 863                        ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
 864                        return ide_started;
 865        }
 866
 867        return ide_stopped;
 868}
 869
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.