ide-tape: remove idetape_init_rq()
[safe/jmp/linux-2.6] / drivers / ide / ide-tape.c
index 7907a1e..83014ab 100644 (file)
@@ -15,6 +15,8 @@
  * Documentation/ide/ChangeLog.ide-tape.1995-2002
  */
 
+#define DRV_NAME "ide-tape"
+
 #define IDETAPE_VERSION "1.20"
 
 #include <linux/module.h>
@@ -195,23 +197,6 @@ enum {
 #define IDETAPE_BLOCK_DESCRIPTOR       0
 #define IDETAPE_CAPABILITIES_PAGE      0x2a
 
-/* Tape flag bits values. */
-enum {
-       IDETAPE_FLAG_IGNORE_DSC         = (1 << 0),
-       /* 0 When the tape position is unknown */
-       IDETAPE_FLAG_ADDRESS_VALID      = (1 << 1),
-       /* Device already opened */
-       IDETAPE_FLAG_BUSY               = (1 << 2),
-       /* Attempt to auto-detect the current user block size */
-       IDETAPE_FLAG_DETECT_BS          = (1 << 3),
-       /* Currently on a filemark */
-       IDETAPE_FLAG_FILEMARK           = (1 << 4),
-       /* DRQ interrupt device */
-       IDETAPE_FLAG_DRQ_INTERRUPT      = (1 << 5),
-       /* 0 = no tape is loaded, so we don't rewind after ejecting */
-       IDETAPE_FLAG_MEDIUM_PRESENT     = (1 << 6),
-};
-
 /*
  * Most of our global data which we need to save even as we leave the driver due
  * to an interrupt or a timer event is stored in the struct defined below.
@@ -312,8 +297,6 @@ typedef struct ide_tape_obj {
        /* Wasted space in each stage */
        int excess_bh_size;
 
-       /* Status/Action flags: long for set_bit */
-       unsigned long flags;
        /* protects the ide-tape queue */
        spinlock_t lock;
 
@@ -341,24 +324,31 @@ static struct class *idetape_sysfs_class;
 #define ide_tape_g(disk) \
        container_of((disk)->private_data, struct ide_tape_obj, driver)
 
+static void ide_tape_release(struct kref *);
+
 static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
 {
        struct ide_tape_obj *tape = NULL;
 
        mutex_lock(&idetape_ref_mutex);
        tape = ide_tape_g(disk);
-       if (tape)
-               kref_get(&tape->kref);
+       if (tape) {
+               if (ide_device_get(tape->drive))
+                       tape = NULL;
+               else
+                       kref_get(&tape->kref);
+       }
        mutex_unlock(&idetape_ref_mutex);
        return tape;
 }
 
-static void ide_tape_release(struct kref *);
-
 static void ide_tape_put(struct ide_tape_obj *tape)
 {
+       ide_drive_t *drive = tape->drive;
+
        mutex_lock(&idetape_ref_mutex);
        kref_put(&tape->kref, ide_tape_release);
+       ide_device_put(drive);
        mutex_unlock(&idetape_ref_mutex);
 }
 
@@ -398,7 +388,7 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                count = min(
                        (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
                        bcount);
-               drive->hwif->input_data(drive, NULL, bh->b_data +
+               drive->hwif->tp_ops->input_data(drive, NULL, bh->b_data +
                                        atomic_read(&bh->b_count), count);
                bcount -= count;
                atomic_add(count, &bh->b_count);
@@ -424,7 +414,7 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                        return;
                }
                count = min((unsigned int)pc->b_count, (unsigned int)bcount);
-               drive->hwif->output_data(drive, NULL, pc->b_data, count);
+               drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count);
                bcount -= count;
                pc->b_data += count;
                pc->b_count -= count;
@@ -439,7 +429,7 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
        }
 }
 
-static void idetape_update_buffers(struct ide_atapi_pc *pc)
+static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
@@ -524,7 +514,7 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
                pc->xferred = pc->req_xfer -
                        tape->blk_size *
                        get_unaligned_be32(&sense[3]);
-               idetape_update_buffers(pc);
+               idetape_update_buffers(drive, pc);
        }
 
        /*
@@ -585,7 +575,6 @@ static void ide_tape_kfree_buffer(idetape_tape_t *tape)
                bh = bh->b_reqnext;
                kfree(prev_bh);
        }
-       kfree(tape->merge_bh);
 }
 
 static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
@@ -627,6 +616,9 @@ static void ide_tape_callback(ide_drive_t *drive)
 
        debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
+       if (tape->failed_pc == pc)
+               tape->failed_pc = NULL;
+
        if (pc->c[0] == REQUEST_SENSE) {
                if (uptodate)
                        idetape_analyze_error(drive, pc->buf);
@@ -662,15 +654,15 @@ static void ide_tape_callback(ide_drive_t *drive)
                if (readpos[0] & 0x4) {
                        printk(KERN_INFO "ide-tape: Block location is unknown"
                                         "to the tape\n");
-                       clear_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags);
+                       clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
                        uptodate = 0;
                } else {
                        debug_log(DBG_SENSE, "Block Location - %u\n",
-                                       be32_to_cpu(*(u32 *)&readpos[4]));
+                                       be32_to_cpup((__be32 *)&readpos[4]));
 
                        tape->partition = readpos[1];
-                       tape->first_frame = be32_to_cpu(*(u32 *)&readpos[4]);
-                       set_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags);
+                       tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]);
+                       set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
                }
        }
 
@@ -687,7 +679,6 @@ static void idetape_init_pc(struct ide_atapi_pc *pc)
        pc->buf_size = IDETAPE_PC_BUFFER_SIZE;
        pc->bh = NULL;
        pc->b_data = NULL;
-       pc->callback = ide_tape_callback;
 }
 
 static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
@@ -698,13 +689,6 @@ static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
        pc->req_xfer = 20;
 }
 
-static void idetape_init_rq(struct request *rq, u8 cmd)
-{
-       blk_rq_init(NULL, rq);
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd[0] = cmd;
-}
-
 /*
  * Generate a new packet command request in front of the request queue, before
  * the current request, so that it will be processed immediately, on the next
@@ -725,10 +709,13 @@ static void idetape_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
 {
        struct ide_tape_obj *tape = drive->driver_data;
 
-       idetape_init_rq(rq, REQ_IDETAPE_PC1);
+       blk_rq_init(NULL, rq);
+       rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->cmd_flags |= REQ_PREEMPT;
        rq->buffer = (char *) pc;
        rq->rq_disk = tape->disk;
+       memcpy(rq->cmd, pc->c, 12);
+       rq->cmd[13] = REQ_IDETAPE_PC1;
        ide_do_drive_cmd(drive, rq);
 }
 
@@ -739,7 +726,6 @@ static void idetape_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
  */
 static void idetape_retry_pc(ide_drive_t *drive)
 {
-       idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc;
        struct request *rq;
 
@@ -747,7 +733,7 @@ static void idetape_retry_pc(ide_drive_t *drive)
        pc = idetape_next_pc_storage(drive);
        rq = idetape_next_rq_storage(drive);
        idetape_create_request_sense_cmd(pc);
-       set_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags);
+       set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
        idetape_queue_pc_head(drive, pc, rq);
 }
 
@@ -765,7 +751,26 @@ static void idetape_postpone_request(ide_drive_t *drive)
        ide_stall_queue(drive, tape->dsc_poll_freq);
 }
 
-typedef void idetape_io_buf(ide_drive_t *, struct ide_atapi_pc *, unsigned int);
+static void ide_tape_handle_dsc(ide_drive_t *drive)
+{
+       idetape_tape_t *tape = drive->driver_data;
+
+       /* Media access command */
+       tape->dsc_polling_start = jiffies;
+       tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
+       tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
+       /* Allow ide.c to handle other requests */
+       idetape_postpone_request(drive);
+}
+
+static void ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+                               unsigned int bcount, int write)
+{
+       if (write)
+               idetape_output_buffers(drive, pc, bcount);
+       else
+               idetape_input_buffers(drive, pc, bcount);
+}
 
 /*
  * This is the usual interrupt handler which will be called during a packet
@@ -776,139 +781,11 @@ typedef void idetape_io_buf(ide_drive_t *, struct ide_atapi_pc *, unsigned int);
  */
 static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = tape->pc;
-       xfer_func_t *xferfunc;
-       idetape_io_buf *iobuf;
-       unsigned int temp;
-       u16 bcount;
-       u8 stat, ireason;
-
-       debug_log(DBG_PROCS, "Enter %s - interrupt handler\n", __func__);
-
-       /* Clear the interrupt */
-       stat = ide_read_status(drive);
-
-       if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
-               if (hwif->dma_ops->dma_end(drive) || (stat & ERR_STAT)) {
-                       pc->flags |= PC_FLAG_DMA_ERROR;
-               } else {
-                       pc->xferred = pc->req_xfer;
-                       idetape_update_buffers(pc);
-               }
-               debug_log(DBG_PROCS, "DMA finished\n");
-
-       }
-
-       /* No more interrupts */
-       if ((stat & DRQ_STAT) == 0) {
-               debug_log(DBG_SENSE, "Packet command completed, %d bytes"
-                               " transferred\n", pc->xferred);
-
-               pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
-               local_irq_enable_in_hardirq();
-
-               if ((stat & ERR_STAT) && pc->c[0] == REQUEST_SENSE)
-                       stat &= ~ERR_STAT;
-               if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
-                       /* Error detected */
-                       debug_log(DBG_ERR, "%s: I/O error\n", tape->name);
-
-                       if (pc->c[0] == REQUEST_SENSE) {
-                               printk(KERN_ERR "%s: I/O error in request sense"
-                                               " command\n", drive->name);
-                               return ide_do_reset(drive);
-                       }
-                       debug_log(DBG_ERR, "[cmd %x]: check condition\n",
-                                       pc->c[0]);
-
-                       /* Retry operation */
-                       idetape_retry_pc(drive);
-                       return ide_stopped;
-               }
-               pc->error = 0;
-               if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) &&
-                   (stat & SEEK_STAT) == 0) {
-                       /* Media access command */
-                       tape->dsc_polling_start = jiffies;
-                       tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
-                       tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-                       /* Allow ide.c to handle other requests */
-                       idetape_postpone_request(drive);
-                       return ide_stopped;
-               }
-               if (tape->failed_pc == pc)
-                       tape->failed_pc = NULL;
-               /* Command finished - Call the callback function */
-               pc->callback(drive);
-               return ide_stopped;
-       }
-
-       if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
-               pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
-               printk(KERN_ERR "%s: The device wants to issue more interrupts "
-                               "in DMA mode\n", drive->name);
-               ide_dma_off(drive);
-               return ide_do_reset(drive);
-       }
-       /* Get the number of bytes to transfer on this interrupt. */
-       bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) |
-                 hwif->INB(hwif->io_ports.lbam_addr);
-
-       ireason = hwif->INB(hwif->io_ports.nsect_addr);
-
-       if (ireason & CD) {
-               printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__);
-               return ide_do_reset(drive);
-       }
-       if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
-               /* Hopefully, we will never get here */
-               printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
-                               "to %s!\n", drive->name,
-                               (ireason & IO) ? "Write" : "Read",
-                               (ireason & IO) ? "Read" : "Write");
-               return ide_do_reset(drive);
-       }
-       if (!(pc->flags & PC_FLAG_WRITING)) {
-               /* Reading - Check that we have enough space */
-               temp = pc->xferred + bcount;
-               if (temp > pc->req_xfer) {
-                       if (temp > pc->buf_size) {
-                               printk(KERN_ERR "%s: The device wants to send "
-                                               "us more data than expected - "
-                                               "discarding data\n",
-                                               drive->name);
-                               ide_pad_transfer(drive, 0, bcount);
-                               ide_set_handler(drive, &idetape_pc_intr,
-                                               IDETAPE_WAIT_CMD, NULL);
-                               return ide_started;
-                       }
-                       debug_log(DBG_SENSE, "The device wants to send us more "
-                               "data than expected - allowing transfer\n");
-               }
-               iobuf = &idetape_input_buffers;
-               xferfunc = hwif->input_data;
-       } else {
-               iobuf = &idetape_output_buffers;
-               xferfunc = hwif->output_data;
-       }
 
-       if (pc->bh)
-               iobuf(drive, pc, bcount);
-       else
-               xferfunc(drive, NULL, pc->cur_pos, bcount);
-
-       /* Update the current position */
-       pc->xferred += bcount;
-       pc->cur_pos += bcount;
-
-       debug_log(DBG_SENSE, "[cmd %x] transferred %d bytes on that intr.\n",
-                       pc->c[0], bcount);
-
-       /* And set the interrupt handler again */
-       ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
-       return ide_started;
+       return ide_pc_intr(drive, tape->pc, idetape_pc_intr, IDETAPE_WAIT_CMD,
+                          NULL, idetape_update_buffers, idetape_retry_pc,
+                          ide_tape_handle_dsc, ide_tape_io_buffers);
 }
 
 /*
@@ -993,7 +870,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
                        pc->error = IDETAPE_ERROR_GENERAL;
                }
                tape->failed_pc = NULL;
-               pc->callback(drive);
+               drive->pc_callback(drive);
                return ide_stopped;
        }
        debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
@@ -1033,14 +910,15 @@ static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
 
 static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc = tape->pc;
        u8 stat;
 
-       stat = ide_read_status(drive);
+       stat = hwif->tp_ops->read_status(hwif);
 
-       if (stat & SEEK_STAT) {
-               if (stat & ERR_STAT) {
+       if (stat & ATA_DSC) {
+               if (stat & ATA_ERR) {
                        /* Error detected */
                        if (pc->c[0] != TEST_UNIT_READY)
                                printk(KERN_ERR "ide-tape: %s: I/O error, ",
@@ -1050,63 +928,57 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
                        return ide_stopped;
                }
                pc->error = 0;
-               if (tape->failed_pc == pc)
-                       tape->failed_pc = NULL;
        } else {
                pc->error = IDETAPE_ERROR_GENERAL;
                tape->failed_pc = NULL;
        }
-       pc->callback(drive);
+       drive->pc_callback(drive);
        return ide_stopped;
 }
 
-static void idetape_create_read_cmd(idetape_tape_t *tape,
-               struct ide_atapi_pc *pc,
-               unsigned int length, struct idetape_bh *bh)
+static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
+                                  struct ide_atapi_pc *pc, struct request *rq,
+                                  u8 opcode)
 {
-       idetape_init_pc(pc);
-       pc->c[0] = READ_6;
-       put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
-       pc->c[1] = 1;
-       pc->bh = bh;
-       atomic_set(&bh->b_count, 0);
-       pc->buf = NULL;
-       pc->buf_size = length * tape->blk_size;
-       pc->req_xfer = pc->buf_size;
-       if (pc->req_xfer == tape->buffer_size)
-               pc->flags |= PC_FLAG_DMA_OK;
-}
+       struct idetape_bh *bh = (struct idetape_bh *)rq->special;
+       unsigned int length = rq->current_nr_sectors;
 
-static void idetape_create_write_cmd(idetape_tape_t *tape,
-               struct ide_atapi_pc *pc,
-               unsigned int length, struct idetape_bh *bh)
-{
        idetape_init_pc(pc);
-       pc->c[0] = WRITE_6;
        put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
-       pc->flags |= PC_FLAG_WRITING;
        pc->bh = bh;
-       pc->b_data = bh->b_data;
-       pc->b_count = atomic_read(&bh->b_count);
        pc->buf = NULL;
        pc->buf_size = length * tape->blk_size;
        pc->req_xfer = pc->buf_size;
        if (pc->req_xfer == tape->buffer_size)
                pc->flags |= PC_FLAG_DMA_OK;
+
+       if (opcode == READ_6) {
+               pc->c[0] = READ_6;
+               atomic_set(&bh->b_count, 0);
+       } else if (opcode == WRITE_6) {
+               pc->c[0] = WRITE_6;
+               pc->flags |= PC_FLAG_WRITING;
+               pc->b_data = bh->b_data;
+               pc->b_count = atomic_read(&bh->b_count);
+       }
+
+       memcpy(rq->cmd, pc->c, 12);
 }
 
 static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                                          struct request *rq, sector_t block)
 {
+       ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc = NULL;
        struct request *postponed_rq = tape->postponed_rq;
        u8 stat;
 
-       debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld,"
-                       " current_nr_sectors: %d\n",
-                       rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+       debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu,"
+                       " current_nr_sectors: %u\n",
+                       (unsigned long long)rq->sector, rq->nr_sectors,
+                       rq->current_nr_sectors);
 
        if (!blk_special_request(rq)) {
                /* We do not support buffer cache originated requests. */
@@ -1136,18 +1008,18 @@ 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.
         */
-       stat = ide_read_status(drive);
+       stat = hwif->tp_ops->read_status(hwif);
 
-       if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
-               set_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags);
+       if (!drive->dsc_overlap && !(rq->cmd[13] & REQ_IDETAPE_PC2))
+               set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
 
        if (drive->post_reset == 1) {
-               set_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags);
+               set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
                drive->post_reset = 0;
        }
 
-       if (!test_and_clear_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags) &&
-           (stat & SEEK_STAT) == 0) {
+       if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
+           (stat & ATA_DSC) == 0) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_poll_freq = tape->best_dsc_rw_freq;
@@ -1155,7 +1027,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                } else if (time_after(jiffies, tape->dsc_timeout)) {
                        printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
                                tape->name);
-                       if (rq->cmd[0] & REQ_IDETAPE_PC2) {
+                       if (rq->cmd[13] & REQ_IDETAPE_PC2) {
                                idetape_media_access_finished(drive);
                                return ide_stopped;
                        } else {
@@ -1168,33 +1040,29 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                idetape_postpone_request(drive);
                return ide_stopped;
        }
-       if (rq->cmd[0] & REQ_IDETAPE_READ) {
+       if (rq->cmd[13] & REQ_IDETAPE_READ) {
                pc = idetape_next_pc_storage(drive);
-               idetape_create_read_cmd(tape, pc, rq->current_nr_sectors,
-                                       (struct idetape_bh *)rq->special);
+               ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
                goto out;
        }
-       if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
+       if (rq->cmd[13] & REQ_IDETAPE_WRITE) {
                pc = idetape_next_pc_storage(drive);
-               idetape_create_write_cmd(tape, pc, rq->current_nr_sectors,
-                                        (struct idetape_bh *)rq->special);
+               ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
                goto out;
        }
-       if (rq->cmd[0] & REQ_IDETAPE_PC1) {
+       if (rq->cmd[13] & REQ_IDETAPE_PC1) {
                pc = (struct ide_atapi_pc *) rq->buffer;
-               rq->cmd[0] &= ~(REQ_IDETAPE_PC1);
-               rq->cmd[0] |= REQ_IDETAPE_PC2;
+               rq->cmd[13] &= ~(REQ_IDETAPE_PC1);
+               rq->cmd[13] |= REQ_IDETAPE_PC2;
                goto out;
        }
-       if (rq->cmd[0] & REQ_IDETAPE_PC2) {
+       if (rq->cmd[13] & REQ_IDETAPE_PC2) {
                idetape_media_access_finished(drive);
                return ide_stopped;
        }
        BUG();
-out:
-       if (test_bit(IDETAPE_FLAG_DRQ_INTERRUPT, &tape->flags))
-               pc->flags |= PC_FLAG_DRQ_INTERRUPT;
 
+out:
        return idetape_issue_pc(drive, pc);
 }
 
@@ -1398,8 +1266,9 @@ static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd[0] = REQ_IDETAPE_PC1;
+       rq->cmd[13] = REQ_IDETAPE_PC1;
        rq->buffer = (char *)pc;
+       memcpy(rq->cmd, pc->c, 12);
        error = blk_execute_rq(drive->queue, tape->disk, rq, 0);
        blk_put_request(rq);
        return error;
@@ -1421,7 +1290,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
        int load_attempted = 0;
 
        /* Wait for the tape to become ready */
-       set_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags);
+       set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
        timeout += jiffies;
        while (time_before(jiffies, timeout)) {
                idetape_create_test_unit_ready_cmd(&pc);
@@ -1514,7 +1383,7 @@ static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
        if (tape->chrdev_dir != IDETAPE_DIR_READ)
                return;
 
-       clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags);
+       clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags);
        tape->merge_bh_size = 0;
        if (tape->merge_bh != NULL) {
                ide_tape_kfree_buffer(tape);
@@ -1582,7 +1451,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd[0] = cmd;
+       rq->cmd[13] = cmd;
        rq->rq_disk = tape->disk;
        rq->special = (void *)bh;
        rq->sector = tape->first_frame;
@@ -1753,7 +1622,7 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
        debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
 
        /* If we are at a filemark, return a read length of 0 */
-       if (test_bit(IDETAPE_FLAG_FILEMARK, &tape->flags))
+       if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
                return 0;
 
        idetape_init_read(drive);
@@ -1863,7 +1732,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
 
        if (tape->chrdev_dir == IDETAPE_DIR_READ) {
                tape->merge_bh_size = 0;
-               if (test_and_clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags))
+               if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
                        ++count;
                ide_tape_discard_merge_buffer(drive, 0);
        }
@@ -1918,7 +1787,7 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
        debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
        if (tape->chrdev_dir != IDETAPE_DIR_READ) {
-               if (test_bit(IDETAPE_FLAG_DETECT_BS, &tape->flags))
+               if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags))
                        if (count > tape->blk_size &&
                            (count % tape->blk_size) == 0)
                                tape->user_bs_factor = count / tape->blk_size;
@@ -1958,7 +1827,7 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
                tape->merge_bh_size = bytes_read-temp;
        }
 finish:
-       if (!actually_read && test_bit(IDETAPE_FLAG_FILEMARK, &tape->flags)) {
+       if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
                debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
 
                idetape_space_over_filemarks(drive, MTFSF, 1);
@@ -2144,7 +2013,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                                              !IDETAPE_LU_LOAD_MASK);
                retval = idetape_queue_pc_tail(drive, &pc);
                if (!retval)
-                       clear_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags);
+                       clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
                return retval;
        case MTNOP:
                ide_tape_discard_merge_buffer(drive, 0);
@@ -2167,9 +2036,9 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                            mt_count % tape->blk_size)
                                return -EIO;
                        tape->user_bs_factor = mt_count / tape->blk_size;
-                       clear_bit(IDETAPE_FLAG_DETECT_BS, &tape->flags);
+                       clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
                } else
-                       set_bit(IDETAPE_FLAG_DETECT_BS, &tape->flags);
+                       set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
                return 0;
        case MTSEEK:
                ide_tape_discard_merge_buffer(drive, 0);
@@ -2299,9 +2168,12 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
        if (i >= MAX_HWIFS * MAX_DRIVES)
                return -ENXIO;
 
+       lock_kernel();
        tape = ide_tape_chrdev_get(i);
-       if (!tape)
+       if (!tape) {
+               unlock_kernel();
                return -ENXIO;
+       }
 
        debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
 
@@ -2316,20 +2188,20 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
 
        filp->private_data = tape;
 
-       if (test_and_set_bit(IDETAPE_FLAG_BUSY, &tape->flags)) {
+       if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) {
                retval = -EBUSY;
                goto out_put_tape;
        }
 
        retval = idetape_wait_ready(drive, 60 * HZ);
        if (retval) {
-               clear_bit(IDETAPE_FLAG_BUSY, &tape->flags);
+               clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
                printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
                goto out_put_tape;
        }
 
        idetape_read_position(drive);
-       if (!test_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags))
+       if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags))
                (void)idetape_rewind_tape(drive);
 
        /* Read block size and write protect status from drive. */
@@ -2345,7 +2217,7 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
        if (tape->write_prot) {
                if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
                    (filp->f_flags & O_ACCMODE) == O_RDWR) {
-                       clear_bit(IDETAPE_FLAG_BUSY, &tape->flags);
+                       clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
                        retval = -EROFS;
                        goto out_put_tape;
                }
@@ -2360,10 +2232,12 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
                        }
                }
        }
+       unlock_kernel();
        return 0;
 
 out_put_tape:
        ide_tape_put(tape);
+       unlock_kernel();
        return retval;
 }
 
@@ -2403,7 +2277,7 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
                        ide_tape_discard_merge_buffer(drive, 1);
        }
 
-       if (minor < 128 && test_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags))
+       if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags))
                (void) idetape_rewind_tape(drive);
        if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
                if (tape->door_locked == DOOR_LOCKED) {
@@ -2413,56 +2287,17 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
                        }
                }
        }
-       clear_bit(IDETAPE_FLAG_BUSY, &tape->flags);
+       clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
        ide_tape_put(tape);
        unlock_kernel();
        return 0;
 }
 
-/*
- * check the contents of the ATAPI IDENTIFY command results. We return:
- *
- * 1 - If the tape can be supported by us, based on the information we have so
- * far.
- *
- * 0 - If this tape driver is not currently supported by us.
- */
-static int idetape_identify_device(ide_drive_t *drive)
-{
-       u8 gcw[2], protocol, device_type, removable, packet_size;
-
-       if (drive->id_read == 0)
-               return 1;
-
-       *((unsigned short *) &gcw) = drive->id->config;
-
-       protocol        =   (gcw[1] & 0xC0) >> 6;
-       device_type     =    gcw[1] & 0x1F;
-       removable       = !!(gcw[0] & 0x80);
-       packet_size     =    gcw[0] & 0x3;
-
-       /* Check that we can support this device */
-       if (protocol != 2)
-               printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n",
-                               protocol);
-       else if (device_type != 1)
-               printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set "
-                               "to tape\n", device_type);
-       else if (!removable)
-               printk(KERN_ERR "ide-tape: The removable flag is not set\n");
-       else if (packet_size != 0) {
-               printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12"
-                               " bytes\n", packet_size);
-       } else
-               return 1;
-       return 0;
-}
-
 static void idetape_get_inquiry_results(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc pc;
-       char fw_rev[6], vendor_id[10], product_id[18];
+       char fw_rev[4], vendor_id[8], product_id[16];
 
        idetape_create_inquiry_cmd(&pc);
        if (idetape_queue_pc_tail(drive, &pc)) {
@@ -2474,11 +2309,11 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
        memcpy(product_id, &pc.buf[16], 16);
        memcpy(fw_rev, &pc.buf[32], 4);
 
-       ide_fixstring(vendor_id, 10, 0);
-       ide_fixstring(product_id, 18, 0);
-       ide_fixstring(fw_rev, 6, 0);
+       ide_fixstring(vendor_id, 8, 0);
+       ide_fixstring(product_id, 16, 0);
+       ide_fixstring(fw_rev, 4, 0);
 
-       printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n",
+       printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n",
                        drive->name, tape->name, vendor_id, product_id, fw_rev);
 }
 
@@ -2506,23 +2341,23 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive)
        caps = pc.buf + 4 + pc.buf[3];
 
        /* convert to host order and save for later use */
-       speed = be16_to_cpu(*(u16 *)&caps[14]);
-       max_speed = be16_to_cpu(*(u16 *)&caps[8]);
+       speed = be16_to_cpup((__be16 *)&caps[14]);
+       max_speed = be16_to_cpup((__be16 *)&caps[8]);
 
-       put_unaligned(max_speed, (u16 *)&caps[8]);
-       put_unaligned(be16_to_cpu(*(u16 *)&caps[12]), (u16 *)&caps[12]);
-       put_unaligned(speed, (u16 *)&caps[14]);
-       put_unaligned(be16_to_cpu(*(u16 *)&caps[16]), (u16 *)&caps[16]);
+       *(u16 *)&caps[8] = max_speed;
+       *(u16 *)&caps[12] = be16_to_cpup((__be16 *)&caps[12]);
+       *(u16 *)&caps[14] = speed;
+       *(u16 *)&caps[16] = be16_to_cpup((__be16 *)&caps[16]);
 
        if (!speed) {
                printk(KERN_INFO "ide-tape: %s: invalid tape speed "
                                "(assuming 650KB/sec)\n", drive->name);
-               put_unaligned(650, (u16 *)&caps[14]);
+               *(u16 *)&caps[14] = 650;
        }
        if (!max_speed) {
                printk(KERN_INFO "ide-tape: %s: invalid max_speed "
                                "(assuming 650KB/sec)\n", drive->name);
-               put_unaligned(650, (u16 *)&caps[8]);
+               *(u16 *)&caps[8] = 650;
        }
 
        memcpy(&tape->caps, caps, 20);
@@ -2533,28 +2368,56 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive)
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static void idetape_add_settings(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
-                       1, 2, (u16 *)&tape->caps[16], NULL);
-       ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
-                       1, 1, (u16 *)&tape->caps[14], NULL);
-       ide_add_setting(drive, "buffer_size", SETTING_READ, TYPE_INT, 0, 0xffff,
-                       1, 1024, &tape->buffer_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_freq,
-                       NULL);
-       ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
-                       1, &drive->dsc_overlap, NULL);
-       ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
-                       1, 1, &tape->avg_speed, NULL);
-       ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
-                       1, &tape->debug_mask, NULL);
-}
-#else
-static inline void idetape_add_settings(ide_drive_t *drive) { ; }
+#define ide_tape_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+       idetape_tape_t *tape = drive->driver_data; \
+       return tape->field; \
+}
+
+#define ide_tape_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+       idetape_tape_t *tape = drive->driver_data; \
+       tape->field = arg; \
+       return 0; \
+}
+
+#define ide_tape_devset_rw(_name, _min, _max, _field, _mulf, _divf) \
+ide_tape_devset_get(_name, _field) \
+ide_tape_devset_set(_name, _field) \
+__IDE_DEVSET(_name, S_RW, _min, _max, get_##_name, set_##_name, _mulf, _divf)
+
+#define ide_tape_devset_r(_name, _min, _max, _field, _mulf, _divf) \
+ide_tape_devset_get(_name, _field) \
+__IDE_DEVSET(_name, S_READ, _min, _max, get_##_name, NULL, _mulf, _divf)
+
+static int mulf_tdsc(ide_drive_t *drive)       { return 1000; }
+static int divf_tdsc(ide_drive_t *drive)       { return   HZ; }
+static int divf_buffer(ide_drive_t *drive)     { return    2; }
+static int divf_buffer_size(ide_drive_t *drive)        { return 1024; }
+
+ide_devset_rw(dsc_overlap,     0,      1, dsc_overlap);
+
+ide_tape_devset_rw(debug_mask, 0, 0xffff, debug_mask,  NULL, NULL);
+ide_tape_devset_rw(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
+                  best_dsc_rw_freq, mulf_tdsc, divf_tdsc);
+
+ide_tape_devset_r(avg_speed,   0, 0xffff, avg_speed,   NULL, NULL);
+ide_tape_devset_r(speed,       0, 0xffff, caps[14],    NULL, NULL);
+ide_tape_devset_r(buffer,      0, 0xffff, caps[16],    NULL, divf_buffer);
+ide_tape_devset_r(buffer_size, 0, 0xffff, buffer_size, NULL, divf_buffer_size);
+
+static const struct ide_devset *idetape_settings[] = {
+       &ide_devset_avg_speed,
+       &ide_devset_buffer,
+       &ide_devset_buffer_size,
+       &ide_devset_debug_mask,
+       &ide_devset_dsc_overlap,
+       &ide_devset_speed,
+       &ide_devset_tdsc,
+       NULL
+};
 #endif
 
 /*
@@ -2576,6 +2439,8 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        u8 gcw[2];
        u16 *ctl = (u16 *)&tape->caps[12];
 
+       drive->pc_callback = ide_tape_callback;
+
        spin_lock_init(&tape->lock);
        drive->dsc_overlap = 1;
        if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
@@ -2584,7 +2449,7 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
                drive->dsc_overlap = 0;
        }
        /* Seagate Travan drives do not support DSC overlap. */
-       if (strstr(drive->id->model, "Seagate STT3401"))
+       if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401"))
                drive->dsc_overlap = 0;
        tape->minor = minor;
        tape->name[0] = 'h';
@@ -2592,11 +2457,12 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        tape->name[2] = '0' + minor;
        tape->chrdev_dir = IDETAPE_DIR_NONE;
        tape->pc = tape->pc_stack;
-       *((unsigned short *) &gcw) = drive->id->config;
+
+       *((u16 *)&gcw) = drive->id[ATA_ID_CONFIG];
 
        /* Command packet DRQ type */
        if (((gcw[0] & 0x60) >> 5) == 1)
-               set_bit(IDETAPE_FLAG_DRQ_INTERRUPT, &tape->flags);
+               set_bit(IDE_AFLAG_DRQ_INTERRUPT, &drive->atapi_flags);
 
        idetape_get_inquiry_results(drive);
        idetape_get_mode_sense_results(drive);
@@ -2634,7 +2500,7 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
                tape->best_dsc_rw_freq * 1000 / HZ,
                drive->using_dma ? ", DMA":"");
 
-       idetape_add_settings(drive);
+       ide_proc_register_driver(drive, tape->driver);
 }
 
 static void ide_tape_remove(ide_drive_t *drive)
@@ -2699,13 +2565,12 @@ static ide_driver_t idetape_driver = {
        .remove                 = ide_tape_remove,
        .version                = IDETAPE_VERSION,
        .media                  = ide_tape,
-       .supports_dsc_overlap   = 1,
        .do_request             = idetape_do_request,
        .end_request            = idetape_end_request,
        .error                  = __ide_error,
-       .abort                  = __ide_abort,
 #ifdef CONFIG_IDE_PROC_FS
        .proc                   = idetape_proc,
+       .settings               = idetape_settings,
 #endif
 };
 
@@ -2768,11 +2633,11 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        if (!strstr("ide-tape", drive->driver_req))
                goto failed;
-       if (!drive->present)
-               goto failed;
+
        if (drive->media != ide_tape)
                goto failed;
-       if (!idetape_identify_device(drive)) {
+
+       if (drive->id_read == 1 && !ide_check_atapi_device(drive, DRV_NAME)) {
                printk(KERN_ERR "ide-tape: %s: not supported by this version of"
                                " the driver\n", drive->name);
                goto failed;
@@ -2790,8 +2655,6 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_proc_register_driver(drive, &idetape_driver);
-
        kref_init(&tape->kref);
 
        tape->drive = drive;
@@ -2810,10 +2673,12 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        idetape_setup(drive, tape, minor);
 
-       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);
+       device_create_drvdata(idetape_sysfs_class, &drive->gendev,
+                             MKDEV(IDETAPE_MAJOR, minor), NULL,
+                             "%s", tape->name);
+       device_create_drvdata(idetape_sysfs_class, &drive->gendev,
+                             MKDEV(IDETAPE_MAJOR, minor + 128), NULL,
+                             "n%s", tape->name);
 
        g->fops = &idetape_block_ops;
        ide_register_region(g);