[PATCH] rt2x00: Implement SW diversity
[safe/jmp/linux-2.6] / drivers / ide / ide-tape.c
index 0ac7eb8..d71a584 100644 (file)
 
 #define IDETAPE_VERSION "1.19"
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/major.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -565,7 +565,7 @@ typedef struct os_dat_s {
  *     The following parameter is used to select the point in the internal
  *     tape fifo in which we will start to refill the buffer. Decreasing
  *     the following parameter will improve the system's latency and
- *     interactive response, while using a high value might improve sytem
+ *     interactive response, while using a high value might improve system
  *     throughput.
  */
 #define IDETAPE_FIFO_THRESHOLD                 2
@@ -615,17 +615,6 @@ typedef struct os_dat_s {
 /*************************** End of tunable parameters ***********************/
 
 /*
- *     Debugging/Performance analysis
- *
- *     I/O trace support
- */
-#define USE_IOTRACE    0
-#if USE_IOTRACE
-#include <linux/io_trace.h>
-#define IO_IDETAPE_FIFO        500
-#endif
-
-/*
  *     Read/Write error simulation
  */
 #define SIMULATE_ERRORS                        0
@@ -640,7 +629,7 @@ typedef enum {
 } idetape_chrdev_direction_t;
 
 struct idetape_bh {
-       unsigned short b_size;
+       u32 b_size;
        atomic_t b_count;
        struct idetape_bh *b_reqnext;
        char *b_data;
@@ -1011,7 +1000,7 @@ typedef struct ide_tape_obj {
          int debug_level; 
 } idetape_tape_t;
 
-static DECLARE_MUTEX(idetape_ref_sem);
+static DEFINE_MUTEX(idetape_ref_mutex);
 
 static struct class *idetape_sysfs_class;
 
@@ -1024,11 +1013,11 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
 {
        struct ide_tape_obj *tape = NULL;
 
-       down(&idetape_ref_sem);
+       mutex_lock(&idetape_ref_mutex);
        tape = ide_tape_g(disk);
        if (tape)
                kref_get(&tape->kref);
-       up(&idetape_ref_sem);
+       mutex_unlock(&idetape_ref_mutex);
        return tape;
 }
 
@@ -1036,9 +1025,9 @@ static void ide_tape_release(struct kref *);
 
 static void ide_tape_put(struct ide_tape_obj *tape)
 {
-       down(&idetape_ref_sem);
+       mutex_lock(&idetape_ref_mutex);
        kref_put(&tape->kref, ide_tape_release);
-       up(&idetape_ref_sem);
+       mutex_unlock(&idetape_ref_mutex);
 }
 
 /*
@@ -1290,11 +1279,11 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
 {
        struct ide_tape_obj *tape = NULL;
 
-       down(&idetape_ref_sem);
+       mutex_lock(&idetape_ref_mutex);
        tape = idetape_devs[i];
        if (tape)
                kref_get(&tape->kref);
-       up(&idetape_ref_sem);
+       mutex_unlock(&idetape_ref_mutex);
        return tape;
 }
 
@@ -1701,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
        if (error)
                tape->failed_pc = NULL;
 
+       if (!blk_special_request(rq)) {
+               ide_end_request(drive, uptodate, nr_sects);
+               return 0;
+       }
+
        spin_lock_irqsave(&tape->spinlock, flags);
 
        /* The request was a pipelined data transfer request */
@@ -1776,7 +1770,7 @@ static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 static void idetape_init_rq(struct request *rq, u8 cmd)
 {
        memset(rq, 0, sizeof(*rq));
-       rq->flags = REQ_SPECIAL;
+       rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->cmd[0] = cmd;
 }
 
@@ -1819,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc;
        struct request *rq;
-       atapi_error_t error;
 
-       error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+       (void)drive->hwif->INB(IDE_ERROR_REG);
        pc = idetape_next_pc_storage(drive);
        rq = idetape_next_rq_storage(drive);
        idetape_create_request_sense_cmd(pc);
@@ -1859,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
-       atapi_status_t status;
-       atapi_bcount_t bcount;
-       atapi_ireason_t ireason;
        idetape_pc_t *pc = tape->pc;
-
        unsigned int temp;
 #if SIMULATE_ERRORS
        static int error_sim_count = 0;
 #endif
+       u16 bcount;
+       u8 stat, ireason;
 
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 4)
@@ -1876,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 #endif /* IDETAPE_DEBUG_LOG */ 
 
        /* Clear the interrupt */
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = hwif->INB(IDE_STATUS_REG);
 
        if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-               if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
+               if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
                        /*
                         * A DMA error is sometimes expected. For example,
                         * if the tape is crossing a filemark during a
@@ -1913,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
        }
 
        /* No more interrupts */
-       if (!status.b.drq) {
+       if ((stat & DRQ_STAT) == 0) {
 #if IDETAPE_DEBUG_LOG
                if (tape->debug_level >= 2)
                        printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
@@ -1928,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                    (++error_sim_count % 100) == 0) {
                        printk(KERN_INFO "ide-tape: %s: simulating error\n",
                                tape->name);
-                       status.b.check = 1;
+                       stat |= ERR_STAT;
                }
 #endif
-               if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
-                       status.b.check = 0;
-               if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {     /* Error detected */
+               if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+                       stat &= ~ERR_STAT;
+               if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
+                       /* Error detected */
 #if IDETAPE_DEBUG_LOG
                        if (tape->debug_level >= 1)
                                printk(KERN_INFO "ide-tape: %s: I/O error\n",
@@ -1952,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                }
                pc->error = 0;
                if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
-                   !status.b.dsc) {
+                   (stat & SEEK_STAT) == 0) {
                        /* Media access command */
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
@@ -1970,34 +1962,34 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                printk(KERN_ERR "ide-tape: The tape wants to issue more "
                                "interrupts in DMA mode\n");
                printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-               (void)__ide_dma_off(drive);
+               ide_dma_off(drive);
                return ide_do_reset(drive);
        }
        /* Get the number of bytes to transfer on this interrupt. */
-       bcount.b.high = hwif->INB(IDE_BCOUNTH_REG);
-       bcount.b.low = hwif->INB(IDE_BCOUNTL_REG);
+       bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+                 hwif->INB(IDE_BCOUNTL_REG);
 
-       ireason.all = hwif->INB(IDE_IREASON_REG);
+       ireason = hwif->INB(IDE_IREASON_REG);
 
-       if (ireason.b.cod) {
+       if (ireason & CD) {
                printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
                return ide_do_reset(drive);
        }
-       if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+       if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "ide-tape: We wanted to %s, ",
-                       ireason.b.io ? "Write":"Read");
+                               (ireason & IO) ? "Write" : "Read");
                printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
-                       ireason.b.io ? "Read":"Write");
+                               (ireason & IO) ? "Read" : "Write");
                return ide_do_reset(drive);
        }
        if (!test_bit(PC_WRITING, &pc->flags)) {
                /* Reading - Check that we have enough space */
-               temp = pc->actually_transferred + bcount.all;
+               temp = pc->actually_transferred + bcount;
                if (temp > pc->request_transfer) {
                        if (temp > pc->buffer_size) {
                                printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-                               idetape_discard_data(drive, bcount.all);
+                               idetape_discard_data(drive, bcount);
                                ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
                                return ide_started;
                        }
@@ -2009,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
        }
        if (test_bit(PC_WRITING, &pc->flags)) {
                if (pc->bh != NULL)
-                       idetape_output_buffers(drive, pc, bcount.all);
+                       idetape_output_buffers(drive, pc, bcount);
                else
                        /* Write the current buffer */
-                       HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+                       hwif->atapi_output_bytes(drive, pc->current_position,
+                                                bcount);
        } else {
                if (pc->bh != NULL)
-                       idetape_input_buffers(drive, pc, bcount.all);
+                       idetape_input_buffers(drive, pc, bcount);
                else
                        /* Read the current buffer */
-                       HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+                       hwif->atapi_input_bytes(drive, pc->current_position,
+                                               bcount);
        }
        /* Update the current position */
-       pc->actually_transferred += bcount.all;
-       pc->current_position += bcount.all;
+       pc->actually_transferred += bcount;
+       pc->current_position += bcount;
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+               printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
+                                "on that interrupt\n", pc->c[0], bcount);
 #endif
        /* And set the interrupt handler again */
        ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
@@ -2079,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
-       atapi_ireason_t ireason;
        int retries = 100;
        ide_startstop_t startstop;
+       u8 ireason;
 
        if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
                printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
                return startstop;
        }
-       ireason.all = hwif->INB(IDE_IREASON_REG);
-       while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+       ireason = hwif->INB(IDE_IREASON_REG);
+       while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
                printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
                                "a packet command, retrying\n");
                udelay(100);
-               ireason.all = hwif->INB(IDE_IREASON_REG);
+               ireason = hwif->INB(IDE_IREASON_REG);
                if (retries == 0) {
                        printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
                                        "issuing a packet command, ignoring\n");
-                       ireason.b.cod = 1;
-                       ireason.b.io = 0;
+                       ireason |= CD;
+                       ireason &= ~IO;
                }
        }
-       if (!ireason.b.cod || ireason.b.io) {
+       if ((ireason & CD) == 0 || (ireason & IO)) {
                printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
                                "a packet command\n");
                return ide_do_reset(drive);
@@ -2121,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
-       atapi_bcount_t bcount;
        int dma_ok = 0;
+       u16 bcount;
 
 #if IDETAPE_DEBUG_BUGS
        if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
@@ -2171,22 +2166,19 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
        pc->actually_transferred = 0;
        pc->current_position = pc->buffer;
        /* Request to transfer the entire buffer at once */
-       bcount.all = pc->request_transfer;
+       bcount = pc->request_transfer;
 
        if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
                printk(KERN_WARNING "ide-tape: DMA disabled, "
                                "reverting to PIO\n");
-               (void)__ide_dma_off(drive);
+               ide_dma_off(drive);
        }
        if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
                dma_ok = !hwif->dma_setup(drive);
 
-       if (IDE_CONTROL_REG)
-               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-       hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG);    /* Use PIO/DMA */
-       hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-       hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
-       hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+       ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
+                          IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
+
        if (dma_ok)                     /* Will begin DMA later */
                set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
        if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
@@ -2296,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
-       atapi_status_t status;
+       u8 stat;
 
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-       if (status.b.dsc) {
-               if (status.b.check) {
+       stat = drive->hwif->INB(IDE_STATUS_REG);
+       if (stat & SEEK_STAT) {
+               if (stat & ERR_STAT) {
                        /* Error detected */
                        if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
                                printk(KERN_ERR "ide-tape: %s: I/O error, ",
@@ -2335,7 +2327,7 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
        }
        if (time_after(jiffies, tape->insert_time))
                tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-       if (jiffies - tape->avg_time >= HZ) {
+       if (time_after_eq(jiffies, tape->avg_time + HZ)) {
                tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
                tape->avg_size = 0;
                tape->avg_time = jiffies;
@@ -2418,13 +2410,13 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = NULL;
        struct request *postponed_rq = tape->postponed_rq;
-       atapi_status_t status;
+       u8 stat;
 
 #if IDETAPE_DEBUG_LOG
 #if 0
        if (tape->debug_level >= 5)
-               printk(KERN_INFO "ide-tape: rq_status: %d, "
-                       "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status,
+               printk(KERN_INFO "ide-tape:  %d, "
+                       "dev: %s, cmd: %ld, errors: %d\n",
                         rq->rq_disk->disk_name, rq->cmd[0], rq->errors);
 #endif
        if (tape->debug_level >= 2)
@@ -2433,12 +2425,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        rq->sector, rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-       if ((rq->flags & REQ_SPECIAL) == 0) {
+       if (!blk_special_request(rq)) {
                /*
                 * We do not support buffer cache originated requests.
                 */
                printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
-                       "request queue (%ld)\n", drive->name, rq->flags);
+                       "request queue (%d)\n", drive->name, rq->cmd_type);
                ide_end_request(drive, 0, 0);
                return ide_stopped;
        }
@@ -2466,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
         * If the tape is still busy, postpone our request and service
         * the other device meanwhile.
         */
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = drive->hwif->INB(IDE_STATUS_REG);
 
        if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
                set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
@@ -2482,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
        calculate_speeds(drive);
        if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
-           !status.b.dsc) {
+           (stat & SEEK_STAT) == 0) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2496,16 +2488,13 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        } else {
                                return ide_do_reset(drive);
                        }
-               } else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
+               } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
                        tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
                idetape_postpone_request(drive);
                return ide_stopped;
        }
        if (rq->cmd[0] & REQ_IDETAPE_READ) {
                tape->buffer_head++;
-#if USE_IOTRACE
-               IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
                idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
@@ -2513,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        }
        if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
                tape->buffer_head++;
-#if USE_IOTRACE
-               IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
                idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
@@ -2573,11 +2559,11 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
        int pages = tape->pages_per_stage;
        char *b_data = NULL;
 
-       if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+       if ((stage = kmalloc(sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
                return NULL;
        stage->next = NULL;
 
-       bh = stage->bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+       bh = stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
        if (bh == NULL)
                goto abort;
        bh->b_reqnext = NULL;
@@ -2607,7 +2593,7 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
                        continue;
                }
                prev_bh = bh;
-               if ((bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
+               if ((bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
                        free_page((unsigned long) b_data);
                        goto abort;
                }
@@ -2644,21 +2630,23 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
        return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
+       int ret = 0;
 
        while (n) {
 #if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
                        printk(KERN_ERR "ide-tape: bh == NULL in "
                                "idetape_copy_stage_from_user\n");
-                       return;
+                       return 1;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
-               copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
+               if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+                       ret = 1;
                n -= count;
                atomic_add(count, &bh->b_count);
                buf += count;
@@ -2669,23 +2657,26 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t
                }
        }
        tape->bh = bh;
+       return ret;
 }
 
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
+       int ret = 0;
 
        while (n) {
 #if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
                        printk(KERN_ERR "ide-tape: bh == NULL in "
                                "idetape_copy_stage_to_user\n");
-                       return;
+                       return 1;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                count = min(tape->b_count, n);
-               copy_to_user(buf, tape->b_data, count);
+               if  (copy_to_user(buf, tape->b_data, count))
+                       ret = 1;
                n -= count;
                tape->b_data += count;
                tape->b_count -= count;
@@ -2698,6 +2689,7 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf,
                        }
                }
        }
+       return ret;
 }
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
@@ -2758,16 +2750,16 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
  */
 static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
 {
-       DECLARE_COMPLETION(wait);
+       DECLARE_COMPLETION_ONSTACK(wait);
        idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
-       if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) {
+       if (rq == NULL || !blk_special_request(rq)) {
                printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
                return;
        }
 #endif /* IDETAPE_DEBUG_BUGS */
-       rq->waiting = &wait;
+       rq->end_io_data = &wait;
        rq->end_io = blk_end_sync_rq;
        spin_unlock_irq(&tape->spinlock);
        wait_for_completion(&wait);
@@ -3236,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
        idetape_switch_buffers(tape, new_stage);
        idetape_add_stage_tail(drive, new_stage);
        tape->pipeline_head++;
-#if USE_IOTRACE
-       IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
        calculate_speeds(drive);
 
        /*
@@ -3488,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
                idetape_remove_stage_head(drive);
                spin_unlock_irqrestore(&tape->spinlock, flags);
                tape->pipeline_head++;
-#if USE_IOTRACE
-               IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
                calculate_speeds(drive);
        }
 #if IDETAPE_DEBUG_BUGS
@@ -3717,6 +3703,7 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
        ssize_t bytes_read,temp, actually_read = 0, rc;
+       ssize_t ret = 0;
 
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 3)
@@ -3735,7 +3722,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                return (0);
        if (tape->merge_stage_size) {
                actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
-               idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+                       ret = -EFAULT;
                buf += actually_read;
                tape->merge_stage_size -= actually_read;
                count -= actually_read;
@@ -3744,7 +3732,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
                if (bytes_read <= 0)
                        goto finish;
-               idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+                       ret = -EFAULT;
                buf += bytes_read;
                count -= bytes_read;
                actually_read += bytes_read;
@@ -3754,7 +3743,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                if (bytes_read <= 0)
                        goto finish;
                temp = min((unsigned long)count, (unsigned long)bytes_read);
-               idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+                       ret = -EFAULT;
                actually_read += temp;
                tape->merge_stage_size = bytes_read-temp;
        }
@@ -3767,7 +3757,8 @@ finish:
                idetape_space_over_filemarks(drive, MTFSF, 1);
                return 0;
        }
-       return actually_read;
+
+       return (ret) ? ret : actually_read;
 }
 
 static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
@@ -3775,7 +3766,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
 {
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
-       ssize_t retval, actually_written = 0;
+       ssize_t actually_written = 0;
+       ssize_t ret = 0;
 
        /* The drive is write protected. */
        if (tape->write_prot)
@@ -3811,7 +3803,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                 *      some drives (Seagate STT3401A) will return an error.
                 */
                if (drive->dsc_overlap) {
-                       retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+                       ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
                        if (retval < 0) {
                                __idetape_kfree_stage(tape->merge_stage);
                                tape->merge_stage = NULL;
@@ -3832,12 +3824,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
-               idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+                               ret = -EFAULT;
                buf += actually_written;
                tape->merge_stage_size += actually_written;
                count -= actually_written;
 
                if (tape->merge_stage_size == tape->stage_size) {
+                       ssize_t retval;
                        tape->merge_stage_size = 0;
                        retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
                        if (retval <= 0)
@@ -3845,7 +3839,9 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                }
        }
        while (count >= tape->stage_size) {
-               idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
+               ssize_t retval;
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+                       ret = -EFAULT;
                buf += tape->stage_size;
                count -= tape->stage_size;
                retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
@@ -3855,10 +3851,11 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
        }
        if (count) {
                actually_written += count;
-               idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+                       ret = -EFAULT;
                tape->merge_stage_size += count;
        }
-       return (actually_written);
+       return (ret) ? ret : actually_written;
 }
 
 static int idetape_write_filemark (ide_drive_t *drive)
@@ -4544,28 +4541,33 @@ static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
        printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
+#ifdef CONFIG_IDE_PROC_FS
 static void idetape_add_settings (ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
 /*
- *                     drive   setting name    read/write      ioctl   ioctl           data type       min                     max                     mul_factor                      div_factor                      data pointer                            set function
+ *                     drive   setting name            read/write      data type       min                     max                     mul_factor                      div_factor      data pointer                            set function
  */
-       ide_add_setting(drive,  "buffer",       SETTING_READ,   -1,     -1,             TYPE_SHORT,     0,                      0xffff,                 1,                              2,                              &tape->capabilities.buffer_size,        NULL);
-       ide_add_setting(drive,  "pipeline_min", SETTING_RW,     -1,     -1,             TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->min_pipeline,                    NULL);
-       ide_add_setting(drive,  "pipeline",     SETTING_RW,     -1,     -1,             TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->max_stages,                      NULL);
-       ide_add_setting(drive,  "pipeline_max", SETTING_RW,     -1,     -1,             TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->max_pipeline,                    NULL);
-       ide_add_setting(drive,  "pipeline_used",SETTING_READ,   -1,     -1,             TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->nr_stages,                       NULL);
-       ide_add_setting(drive,  "pipeline_pending",SETTING_READ,-1,     -1,             TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->nr_pending_stages,               NULL);
-       ide_add_setting(drive,  "speed",        SETTING_READ,   -1,     -1,             TYPE_SHORT,     0,                      0xffff,                 1,                              1,                              &tape->capabilities.speed,              NULL);
-       ide_add_setting(drive,  "stage",        SETTING_READ,   -1,     -1,             TYPE_INT,       0,                      0xffff,                 1,                              1024,                           &tape->stage_size,                      NULL);
-       ide_add_setting(drive,  "tdsc",         SETTING_RW,     -1,     -1,             TYPE_INT,       IDETAPE_DSC_RW_MIN,     IDETAPE_DSC_RW_MAX,     1000,                           HZ,                             &tape->best_dsc_rw_frequency,           NULL);
-       ide_add_setting(drive,  "dsc_overlap",  SETTING_RW,     -1,     -1,             TYPE_BYTE,      0,                      1,                      1,                              1,                              &drive->dsc_overlap,                    NULL);
-       ide_add_setting(drive,  "pipeline_head_speed_c",SETTING_READ,   -1,     -1,     TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->controlled_pipeline_head_speed,  NULL);
-       ide_add_setting(drive,  "pipeline_head_speed_u",SETTING_READ,   -1,     -1,     TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->uncontrolled_pipeline_head_speed,        NULL);
-       ide_add_setting(drive,  "avg_speed",    SETTING_READ,   -1,     -1,             TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->avg_speed,               NULL);
-       ide_add_setting(drive,  "debug_level",SETTING_RW,       -1,     -1,             TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->debug_level,             NULL);
+       ide_add_setting(drive,  "buffer",               SETTING_READ,   TYPE_SHORT,     0,                      0xffff,                 1,                              2,              &tape->capabilities.buffer_size,        NULL);
+       ide_add_setting(drive,  "pipeline_min",         SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->min_pipeline,                    NULL);
+       ide_add_setting(drive,  "pipeline",             SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->max_stages,                      NULL);
+       ide_add_setting(drive,  "pipeline_max",         SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->max_pipeline,                    NULL);
+       ide_add_setting(drive,  "pipeline_used",        SETTING_READ,   TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->nr_stages,                       NULL);
+       ide_add_setting(drive,  "pipeline_pending",     SETTING_READ,   TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->nr_pending_stages,               NULL);
+       ide_add_setting(drive,  "speed",                SETTING_READ,   TYPE_SHORT,     0,                      0xffff,                 1,                              1,              &tape->capabilities.speed,              NULL);
+       ide_add_setting(drive,  "stage",                SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1024,           &tape->stage_size,                      NULL);
+       ide_add_setting(drive,  "tdsc",                 SETTING_RW,     TYPE_INT,       IDETAPE_DSC_RW_MIN,     IDETAPE_DSC_RW_MAX,     1000,                           HZ,             &tape->best_dsc_rw_frequency,           NULL);
+       ide_add_setting(drive,  "dsc_overlap",          SETTING_RW,     TYPE_BYTE,      0,                      1,                      1,                              1,              &drive->dsc_overlap,                    NULL);
+       ide_add_setting(drive,  "pipeline_head_speed_c",SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->controlled_pipeline_head_speed,  NULL);
+       ide_add_setting(drive,  "pipeline_head_speed_u",SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->uncontrolled_pipeline_head_speed,NULL);
+       ide_add_setting(drive,  "avg_speed",            SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->avg_speed,                       NULL);
+       ide_add_setting(drive,  "debug_level",          SETTING_RW,     TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->debug_level,                     NULL);
 }
+#else
+static inline void idetape_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *     ide_setup is called to:
@@ -4682,18 +4684,15 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
        idetape_add_settings(drive);
 }
 
-static int ide_tape_remove(struct device *dev)
+static void ide_tape_remove(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        idetape_tape_t *tape = drive->driver_data;
 
-       ide_unregister_subdriver(drive, tape->driver);
+       ide_proc_unregister_driver(drive, tape->driver);
 
        ide_unregister_region(tape->disk);
 
        ide_tape_put(tape);
-
-       return 0;
 }
 
 static void ide_tape_release(struct kref *kref)
@@ -4706,21 +4705,15 @@ static void ide_tape_release(struct kref *kref)
 
        drive->dsc_overlap = 0;
        drive->driver_data = NULL;
-       class_device_destroy(idetape_sysfs_class,
-                       MKDEV(IDETAPE_MAJOR, tape->minor));
-       class_device_destroy(idetape_sysfs_class,
-                       MKDEV(IDETAPE_MAJOR, tape->minor + 128));
-       devfs_remove("%s/mt", drive->devfs_name);
-       devfs_remove("%s/mtn", drive->devfs_name);
-       devfs_unregister_tape(g->number);
+       device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
+       device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
        idetape_devs[tape->minor] = NULL;
        g->private_data = NULL;
        put_disk(g);
        kfree(tape);
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idetape_read_name
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -4738,23 +4731,18 @@ static ide_proc_entry_t idetape_proc[] = {
        { "name",       S_IFREG|S_IRUGO,        proc_idetape_read_name, NULL },
        { NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define        idetape_proc    NULL
-
 #endif
 
-static int ide_tape_probe(struct device *);
+static int ide_tape_probe(ide_drive_t *);
 
 static ide_driver_t idetape_driver = {
-       .owner                  = THIS_MODULE,
        .gen_driver = {
+               .owner          = THIS_MODULE,
                .name           = "ide-tape",
                .bus            = &ide_bus_type,
-               .probe          = ide_tape_probe,
-               .remove         = ide_tape_remove,
        },
+       .probe                  = ide_tape_probe,
+       .remove                 = ide_tape_remove,
        .version                = IDETAPE_VERSION,
        .media                  = ide_tape,
        .supports_dsc_overlap   = 1,
@@ -4762,13 +4750,15 @@ static ide_driver_t idetape_driver = {
        .end_request            = idetape_end_request,
        .error                  = __ide_error,
        .abort                  = __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
        .proc                   = idetape_proc,
+#endif
 };
 
 /*
  *     Our character device supporting functions, passed to register_chrdev.
  */
-static struct file_operations idetape_fops = {
+static const struct file_operations idetape_fops = {
        .owner          = THIS_MODULE,
        .read           = idetape_chrdev_read,
        .write          = idetape_chrdev_write,
@@ -4781,15 +4771,10 @@ static int idetape_open(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
        struct ide_tape_obj *tape;
-       ide_drive_t *drive;
 
        if (!(tape = ide_tape_get(disk)))
                return -ENXIO;
 
-       drive = tape->drive;
-
-       drive->usage++;
-
        return 0;
 }
 
@@ -4797,9 +4782,6 @@ static int idetape_release(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
        struct ide_tape_obj *tape = ide_tape_g(disk);
-       ide_drive_t *drive = tape->drive;
-
-       drive->usage--;
 
        ide_tape_put(tape);
 
@@ -4825,9 +4807,8 @@ static struct block_device_operations idetape_block_ops = {
        .ioctl          = idetape_ioctl,
 };
 
-static int ide_tape_probe(struct device *dev)
+static int ide_tape_probe(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        idetape_tape_t *tape;
        struct gendisk *g;
        int minor;
@@ -4850,7 +4831,7 @@ static int ide_tape_probe(struct device *dev)
                printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
                printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
        }
-       tape = (idetape_tape_t *) kzalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+       tape = kzalloc(sizeof (idetape_tape_t), GFP_KERNEL);
        if (tape == NULL) {
                printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
                goto failed;
@@ -4862,7 +4843,7 @@ static int ide_tape_probe(struct device *dev)
 
        ide_init_disk(g, drive);
 
-       ide_register_subdriver(drive, &idetape_driver);
+       ide_proc_register_driver(drive, &idetape_driver);
 
        kref_init(&tape->kref);
 
@@ -4874,27 +4855,19 @@ static int ide_tape_probe(struct device *dev)
 
        drive->driver_data = tape;
 
-       down(&idetape_ref_sem);
+       mutex_lock(&idetape_ref_mutex);
        for (minor = 0; idetape_devs[minor]; minor++)
                ;
        idetape_devs[minor] = tape;
-       up(&idetape_ref_sem);
+       mutex_unlock(&idetape_ref_mutex);
 
        idetape_setup(drive, tape, minor);
 
-       class_device_create(idetape_sysfs_class, NULL,
-                       MKDEV(IDETAPE_MAJOR, minor), dev, "%s", tape->name);
-       class_device_create(idetape_sysfs_class, NULL,
-                       MKDEV(IDETAPE_MAJOR, minor + 128), dev, "n%s", tape->name);
-
-       devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
-                       S_IFCHR | S_IRUGO | S_IWUGO,
-                       "%s/mt", drive->devfs_name);
-       devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128),
-                       S_IFCHR | S_IRUGO | S_IWUGO,
-                       "%s/mtn", drive->devfs_name);
+       device_create(idetape_sysfs_class, &drive->gendev,
+                     MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name);
+       device_create(idetape_sysfs_class, &drive->gendev,
+                       MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name);
 
-       g->number = devfs_register_tape(drive->devfs_name);
        g->fops = &idetape_block_ops;
        ide_register_region(g);
 
@@ -4916,10 +4889,7 @@ static void __exit idetape_exit (void)
        unregister_chrdev(IDETAPE_MAJOR, "ht");
 }
 
-/*
- *     idetape_init will register the driver for each tape.
- */
-static int idetape_init (void)
+static int __init idetape_init(void)
 {
        int error = 1;
        idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape");
@@ -4950,6 +4920,7 @@ out:
        return error;
 }
 
+MODULE_ALIAS("ide:*m-tape*");
 module_init(idetape_init);
 module_exit(idetape_exit);
 MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);