return tape;
 }
 
-static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                                 unsigned int bcount)
-{
-       struct idetape_bh *bh = pc->bh;
-       int count;
-
-       if (bcount && bh) {
-               count = min(
-                       (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
-                       bcount);
-               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);
-               if (atomic_read(&bh->b_count) == bh->b_size)
-                       pc->bh = NULL;
-       }
-
-       return bcount;
-}
-
-static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                                  unsigned int bcount)
-{
-       struct idetape_bh *bh = pc->bh;
-       int count;
-
-       if (bcount && bh) {
-               count = min((unsigned int)pc->b_count, (unsigned int)bcount);
-               drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count);
-               bcount -= count;
-               pc->b_data += count;
-               pc->b_count -= count;
-               if (!pc->b_count)
-                       pc->bh = NULL;
-       }
-
-       return bcount;
-}
-
-static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-       struct idetape_bh *bh = pc->bh;
-       unsigned int bcount = pc->xferred;
-
-       if (pc->flags & PC_FLAG_WRITING)
-               return;
-       if (bcount) {
-               if (bh == NULL || bcount > bh->b_size) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
-                                       __func__);
-                       return;
-               }
-               atomic_set(&bh->b_count, bcount);
-               if (atomic_read(&bh->b_count) == bh->b_size)
-                       pc->bh = NULL;
-       }
-}
-
 /*
  * called on each failed packet command retry to analyze the request sense. We
  * currently do not utilize this information.
                 pc->c[0], tape->sense_key, tape->asc, tape->ascq);
 
        /* Correct pc->xferred by asking the tape.       */
-       if (pc->flags & PC_FLAG_DMA_ERROR) {
+       if (pc->flags & PC_FLAG_DMA_ERROR)
                pc->xferred = pc->req_xfer -
                        tape->blk_size *
                        get_unaligned_be32(&sense[3]);
-               idetape_update_buffers(drive, pc);
-       }
 
        /*
         * If error was the result of a zero-length read or write command,
                }
 
                tape->first_frame += blocks;
-               rq->current_nr_sectors -= blocks;
+               rq->data_len -= blocks * tape->blk_size;
 
                if (pc->error) {
                        uptodate = 0;
        idetape_postpone_request(drive);
 }
 
-static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                               unsigned int bcount, int write)
-{
-       unsigned int bleft;
-
-       if (write)
-               bleft = idetape_output_buffers(drive, pc, bcount);
-       else
-               bleft = idetape_input_buffers(drive, pc, bcount);
-
-       return bcount - bleft;
-}
-
 /*
  * Packet Command Interface
  *
        ide_init_pc(pc);
        put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
-       pc->bh = bh;
+       pc->bh = NULL;
        pc->buf = NULL;
        pc->buf_size = length * tape->blk_size;
        pc->req_xfer = pc->buf_size;
                                 struct idetape_bh *bh)
 {
        idetape_tape_t *tape = drive->driver_data;
+       size_t size = blocks * tape->blk_size;
        struct request *rq;
-       int ret, errors;
+       int ret;
 
        debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+       BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE);
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->rq_disk = tape->disk;
        rq->special = (void *)bh;
        rq->sector = tape->first_frame;
-       rq->nr_sectors = blocks;
-       rq->current_nr_sectors = blocks;
+
+       if (size) {
+               ret = blk_rq_map_kern(drive->queue, rq, bh->b_data, size,
+                                     __GFP_WAIT);
+               if (ret)
+                       goto out_put;
+       }
+
        blk_execute_rq(drive->queue, tape->disk, rq, 0);
 
-       errors = rq->errors;
-       ret = tape->blk_size * (blocks - rq->current_nr_sectors);
-       blk_put_request(rq);
+       /* calculate the number of transferred bytes and update bh */
+       size -= rq->data_len;
+       if (cmd == REQ_IDETAPE_READ)
+               atomic_add(size, &bh->b_count);
 
-       if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
-               return 0;
+       ret = size;
+       if (rq->errors == IDE_DRV_ERROR_GENERAL)
+               ret = -EIO;
 
        if (tape->merge_bh)
                idetape_init_merge_buffer(tape);
-       if (errors == IDE_DRV_ERROR_GENERAL)
-               return -EIO;
+out_put:
+       blk_put_request(rq);
        return ret;
 }
 
        u16 *ctl = (u16 *)&tape->caps[12];
 
        drive->pc_callback       = ide_tape_callback;
-       drive->pc_update_buffers = idetape_update_buffers;
-       drive->pc_io_buffers     = ide_tape_io_buffers;
 
        drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;