Merge branch 'bp-remove-pc-buf' into for-next
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Sat, 13 Jun 2009 10:00:54 +0000 (12:00 +0200)
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Sat, 13 Jun 2009 10:00:54 +0000 (12:00 +0200)
Conflicts:
drivers/ide/ide-tape.c

1  2 
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-tape.c
include/linux/ide.h

diff --combined drivers/ide/ide-atapi.c
@@@ -10,6 -10,9 +10,9 @@@
  
  #include <scsi/scsi.h>
  
+ #define DRV_NAME "ide-atapi"
+ #define PFX DRV_NAME ": "
  #ifdef DEBUG
  #define debug_log(fmt, args...) \
        printk(KERN_INFO "ide: " fmt, ## args)
@@@ -74,8 -77,6 +77,6 @@@ EXPORT_SYMBOL_GPL(ide_check_atapi_devic
  void ide_init_pc(struct ide_atapi_pc *pc)
  {
        memset(pc, 0, sizeof(*pc));
-       pc->buf = pc->pc_buf;
-       pc->buf_size = IDE_PC_BUFFER_SIZE;
  }
  EXPORT_SYMBOL_GPL(ide_init_pc);
  
@@@ -84,7 -85,7 +85,7 @@@
   * and wait for it to be serviced.
   */
  int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
-                     struct ide_atapi_pc *pc)
+                     struct ide_atapi_pc *pc, void *buf, unsigned int bufflen)
  {
        struct request *rq;
        int error;
@@@ -93,8 -94,8 +94,8 @@@
        rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->special = (char *)pc;
  
-       if (pc->req_xfer) {
-               error = blk_rq_map_kern(drive->queue, rq, pc->buf, pc->req_xfer,
+       if (buf && bufflen) {
+               error = blk_rq_map_kern(drive->queue, rq, buf, bufflen,
                                        GFP_NOIO);
                if (error)
                        goto put_req;
@@@ -117,7 -118,7 +118,7 @@@ int ide_do_test_unit_ready(ide_drive_t 
        ide_init_pc(&pc);
        pc.c[0] = TEST_UNIT_READY;
  
-       return ide_queue_pc_tail(drive, disk, &pc);
+       return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
  }
  EXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
  
@@@ -132,7 -133,7 +133,7 @@@ int ide_do_start_stop(ide_drive_t *driv
        if (drive->media == ide_tape)
                pc.flags |= PC_FLAG_WAIT_FOR_DSC;
  
-       return ide_queue_pc_tail(drive, disk, &pc);
+       return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
  }
  EXPORT_SYMBOL_GPL(ide_do_start_stop);
  
@@@ -147,7 -148,7 +148,7 @@@ int ide_set_media_lock(ide_drive_t *dri
        pc.c[0] = ALLOW_MEDIUM_REMOVAL;
        pc.c[4] = on;
  
-       return ide_queue_pc_tail(drive, disk, &pc);
+       return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
  }
  EXPORT_SYMBOL_GPL(ide_set_media_lock);
  
@@@ -172,8 -173,6 +173,6 @@@ void ide_prep_sense(ide_drive_t *drive
        unsigned int cmd_len, sense_len;
        int err;
  
-       debug_log("%s: enter\n", __func__);
        switch (drive->media) {
        case ide_floppy:
                cmd_len = 255;
                              GFP_NOIO);
        if (unlikely(err)) {
                if (printk_ratelimit())
-                       printk(KERN_WARNING "%s: failed to map sense buffer\n",
-                              drive->name);
+                       printk(KERN_WARNING PFX "%s: failed to map sense "
+                                           "buffer\n", drive->name);
                return;
        }
  
@@@ -223,7 -222,7 +222,7 @@@ int ide_queue_sense_rq(ide_drive_t *dri
  {
        /* deferred failure from ide_prep_sense() */
        if (!drive->sense_rq_armed) {
-               printk(KERN_WARNING "%s: failed queue sense request\n",
+               printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
                       drive->name);
                return -ENOMEM;
        }
@@@ -255,11 -254,9 +254,9 @@@ void ide_retry_pc(ide_drive_t *drive
        /* init pc from sense_rq */
        ide_init_pc(pc);
        memcpy(pc->c, sense_rq->cmd, 12);
-       pc->buf = bio_data(sense_rq->bio);      /* pointer to mapped address */
-       pc->req_xfer = blk_rq_bytes(sense_rq);
  
        if (drive->media == ide_tape)
 -              set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
 +              drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
  
        /*
         * Push back the failed request and put request sense on top
@@@ -298,7 -295,7 +295,7 @@@ int ide_cd_expiry(ide_drive_t *drive
                break;
        default:
                if (!(rq->cmd_flags & REQ_QUIET))
-                       printk(KERN_INFO "cmd 0x%x timed out\n",
+                       printk(KERN_INFO PFX "cmd 0x%x timed out\n",
                                         rq->cmd[0]);
                wait = 0;
                break;
@@@ -331,6 -328,55 +328,55 @@@ void ide_read_bcount_and_ireason(ide_dr
  }
  EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
  
+ /*
+  * Check the contents of the interrupt reason register and attempt to recover if
+  * there are problems.
+  *
+  * Returns:
+  * - 0 if everything's ok
+  * - 1 if the request has to be terminated.
+  */
+ int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len,
+                     int ireason, int rw)
+ {
+       ide_hwif_t *hwif = drive->hwif;
+       debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw);
+       if (ireason == (!rw << 1))
+               return 0;
+       else if (ireason == (rw << 1)) {
+               printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
+                               drive->name, __func__);
+               if (dev_is_idecd(drive))
+                       ide_pad_transfer(drive, rw, len);
+       } else if (!rw && ireason == ATAPI_COD) {
+               if (dev_is_idecd(drive)) {
+                       /*
+                        * Some drives (ASUS) seem to tell us that status info
+                        * is available.  Just get it and ignore.
+                        */
+                       (void)hwif->tp_ops->read_status(hwif);
+                       return 0;
+               }
+       } else {
+               if (ireason & ATAPI_COD)
+                       printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name,
+                                       __func__);
+               /* drive wants a command packet, or invalid ireason... */
+               printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
+                               drive->name, __func__, ireason);
+       }
+       if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC)
+               rq->cmd_flags |= REQ_FAILED;
+       return 1;
+ }
+ EXPORT_SYMBOL_GPL(ide_check_ireason);
  /*
   * This is the usual interrupt handler which will be called during a packet
   * command.  We will transfer some of the data (as requested by the drive)
@@@ -365,12 -411,12 +411,12 @@@ static ide_startstop_t ide_pc_intr(ide_
  
                if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
                        if (drive->media == ide_floppy)
-                               printk(KERN_ERR "%s: DMA %s error\n",
+                               printk(KERN_ERR PFX "%s: DMA %s error\n",
                                        drive->name, rq_data_dir(pc->rq)
                                                     ? "write" : "read");
                        pc->flags |= PC_FLAG_DMA_ERROR;
                } else
-                       pc->xferred = pc->req_xfer;
+                       rq->resid_len = 0;
                debug_log("%s: DMA finished\n", drive->name);
        }
  
                int uptodate, error;
  
                debug_log("Packet command completed, %d bytes transferred\n",
-                         pc->xferred);
+                         blk_rq_bytes(rq));
  
                pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
  
                                pc->rq->errors++;
  
                        if (rq->cmd[0] == REQUEST_SENSE) {
-                               printk(KERN_ERR "%s: I/O error in request sense"
-                                               " command\n", drive->name);
+                               printk(KERN_ERR PFX "%s: I/O error in request "
+                                               "sense command\n", drive->name);
                                return ide_do_reset(drive);
                        }
  
                if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
                        dsc = 1;
  
 +              /*
 +               * ->pc_callback() might change rq->data_len for
 +               * residual count, cache total length.
 +               */
 +              done = blk_rq_bytes(rq);
 +
                /* Command finished - Call the callback function */
                uptodate = drive->pc_callback(drive, dsc);
  
  
        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);
+               printk(KERN_ERR PFX "%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. */
        ide_read_bcount_and_ireason(drive, &bcount, &ireason);
  
-       if (ireason & ATAPI_COD) {
-               printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__);
+       if (ide_check_ireason(drive, rq, bcount, ireason, write))
                return ide_do_reset(drive);
-       }
-       if (((ireason & ATAPI_IO) == ATAPI_IO) == write) {
-               /* 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 & ATAPI_IO) ? "Write" : "Read",
-                               (ireason & ATAPI_IO) ? "Read" : "Write");
-               return ide_do_reset(drive);
-       }
  
        done = min_t(unsigned int, bcount, cmd->nleft);
        ide_pio_bytes(drive, cmd, write, done);
  
        /* Update transferred byte count */
-       pc->xferred += done;
+       rq->resid_len -= done;
  
        bcount -= done;
  
        if (bcount)
                ide_pad_transfer(drive, write, bcount);
  
-       debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n",
-                 rq->cmd[0], done, bcount);
+       debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n",
+                 rq->cmd[0], done, bcount, rq->resid_len);
  
        /* And set the interrupt handler again */
        ide_set_handler(drive, ide_pc_intr, timeout);
@@@ -515,13 -544,13 +550,13 @@@ static u8 ide_wait_ireason(ide_drive_t 
  
        while (retries-- && ((ireason & ATAPI_COD) == 0 ||
                (ireason & ATAPI_IO))) {
-               printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
+               printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing "
                                "a packet command, retrying\n", drive->name);
                udelay(100);
                ireason = ide_read_ireason(drive);
                if (retries == 0) {
-                       printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
-                                       "a packet command, ignoring\n",
+                       printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing"
+                                       " a packet command, ignoring\n",
                                        drive->name);
                        ireason |= ATAPI_COD;
                        ireason &= ~ATAPI_IO;
@@@ -552,7 -581,7 +587,7 @@@ static ide_startstop_t ide_transfer_pc(
        u8 ireason;
  
        if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
-               printk(KERN_ERR "%s: Strange, packet command initiated yet "
+               printk(KERN_ERR PFX "%s: Strange, packet command initiated yet "
                                "DRQ isn't asserted\n", drive->name);
                return startstop;
        }
                        ireason = ide_wait_ireason(drive, ireason);
  
                if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
-                       printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
-                                       "a packet command\n", drive->name);
+                       printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while "
+                               "issuing a packet command\n", drive->name);
  
                        return ide_do_reset(drive);
                }
@@@ -633,7 -662,7 +668,7 @@@ ide_startstop_t ide_issue_pc(ide_drive_
        ide_hwif_t *hwif = drive->hwif;
        ide_expiry_t *expiry = NULL;
        struct request *rq = hwif->rq;
-       unsigned int timeout;
+       unsigned int timeout, bytes;
        u16 bcount;
        u8 valid_tf;
        u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT);
        } else {
                pc = drive->pc;
  
-               /* We haven't transferred any data yet */
-               pc->xferred = 0;
                valid_tf = IDE_VALID_DEVICE;
-               bcount = ((drive->media == ide_tape) ?
-                               pc->req_xfer :
-                               min(pc->req_xfer, 63 * 1024));
+               bytes = blk_rq_bytes(rq);
+               bcount = ((drive->media == ide_tape) ? bytes
+                                                    : min_t(unsigned int,
+                                                            bytes, 63 * 1024));
+               /* We haven't transferred any data yet */
+               rq->resid_len = bcount;
  
                if (pc->flags & PC_FLAG_DMA_ERROR) {
                        pc->flags &= ~PC_FLAG_DMA_ERROR;
diff --combined drivers/ide/ide-cd.c
@@@ -92,16 -92,16 +92,16 @@@ static void cdrom_saw_media_change(ide_
        drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
  }
  
- static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
-                          struct request_sense *sense)
+ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq)
  {
+       struct request_sense *sense = &drive->sense_data;
        int log = 0;
  
-       ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
        if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
                return 0;
  
+       ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
        switch (sense->sense_key) {
        case NO_SENSE:
        case RECOVERED_ERROR:
  }
  
  static void cdrom_analyze_sense_data(ide_drive_t *drive,
-                             struct request *failed_command,
-                             struct request_sense *sense)
+                                    struct request *failed_command)
  {
+       struct request_sense *sense = &drive->sense_data;
+       struct cdrom_info *info = drive->driver_data;
        unsigned long sector;
        unsigned long bio_sectors;
-       struct cdrom_info *info = drive->driver_data;
  
        ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
                                     sense->error_code, sense->sense_key);
                ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
                                             failed_command->cmd[0]);
  
-       if (!cdrom_log_sense(drive, failed_command, sense))
+       if (!cdrom_log_sense(drive, failed_command))
                return;
  
        /*
                                 (sense->information[2] <<  8) |
                                 (sense->information[3]);
  
 -                      if (drive->queue->hardsect_size == 2048)
 +                      if (queue_logical_block_size(drive->queue) == 2048)
                                /* device sector size is 2K */
                                sector <<= 2;
  
@@@ -225,15 -225,14 +225,14 @@@ static void ide_cd_complete_failed_rq(i
                         * sense pointer set.
                         */
                        memcpy(failed->sense, sense, 18);
-                       sense = failed->sense;
                        failed->sense_len = rq->sense_len;
                }
-               cdrom_analyze_sense_data(drive, failed, sense);
+               cdrom_analyze_sense_data(drive, failed);
  
                if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed)))
                        BUG();
        } else
-               cdrom_analyze_sense_data(drive, NULL, sense);
+               cdrom_analyze_sense_data(drive, NULL);
  }
  
  
@@@ -283,6 -282,7 +282,6 @@@ static int cdrom_decode_status(ide_driv
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = hwif->rq;
        int err, sense_key, do_end_request = 0;
 -      u8 quiet = rq->cmd_flags & REQ_QUIET;
  
        /* get the IDE error register */
        err = ide_read_error(drive);
                } else {
                        cdrom_saw_media_change(drive);
  
 -                      if (blk_fs_request(rq) && !quiet)
 +                      if (blk_fs_request(rq) && !blk_rq_quiet(rq))
                                printk(KERN_ERR PFX "%s: tray open\n",
                                        drive->name);
                }
                 * No point in retrying after an illegal request or data
                 * protect error.
                 */
 -              if (!quiet)
 +              if (!blk_rq_quiet(rq))
                        ide_dump_status(drive, "command error", stat);
                do_end_request = 1;
                break;
                 * No point in re-trying a zillion times on a bad sector.
                 * If we got here the error is not correctable.
                 */
 -              if (!quiet)
 +              if (!blk_rq_quiet(rq))
                        ide_dump_status(drive, "media error "
                                        "(bad sector)", stat);
                do_end_request = 1;
                break;
        case BLANK_CHECK:
                /* disk appears blank? */
 -              if (!quiet)
 +              if (!blk_rq_quiet(rq))
                        ide_dump_status(drive, "media error (blank)",
                                        stat);
                do_end_request = 1;
@@@ -410,50 -410,6 +409,6 @@@ end_request
                return 2;
  }
  
- /*
-  * Check the contents of the interrupt reason register from the cdrom
-  * and attempt to recover if there are problems.  Returns  0 if everything's
-  * ok; nonzero if the request has been terminated.
-  */
- static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
-                               int len, int ireason, int rw)
- {
-       ide_hwif_t *hwif = drive->hwif;
-       ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw);
-       /*
-        * ireason == 0: the drive wants to receive data from us
-        * ireason == 2: the drive is expecting to transfer data to us
-        */
-       if (ireason == (!rw << 1))
-               return 0;
-       else if (ireason == (rw << 1)) {
-               /* whoops... */
-               printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
-                               drive->name, __func__);
-               ide_pad_transfer(drive, rw, len);
-       } else  if (rw == 0 && ireason == 1) {
-               /*
-                * Some drives (ASUS) seem to tell us that status info is
-                * available.  Just get it and ignore.
-                */
-               (void)hwif->tp_ops->read_status(hwif);
-               return 0;
-       } else {
-               /* drive wants a command packet, or invalid ireason... */
-               printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
-                               drive->name, __func__, ireason);
-       }
-       if (rq->cmd_type == REQ_TYPE_ATA_PC)
-               rq->cmd_flags |= REQ_FAILED;
-       return -1;
- }
  static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
  {
        struct request *rq = cmd->rq;
@@@ -645,8 -601,7 +600,7 @@@ static ide_startstop_t cdrom_newpc_intr
                goto out_end;
        }
  
-       /* check which way to transfer data */
-       rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
+       rc = ide_check_ireason(drive, rq, len, ireason, write);
        if (rc)
                goto out_end;
  
  
  out_end:
        if (blk_pc_request(rq) && rc == 0) {
 +              rq->resid_len = 0;
                blk_end_request_all(rq, 0);
                hwif->rq = NULL;
        } else {
  
                /* make sure it's fully ended */
                if (blk_fs_request(rq) == 0) {
 -                      rq->resid_len = blk_rq_bytes(rq) -
 -                              (cmd->nbytes - cmd->nleft);
 +                      rq->resid_len -= cmd->nbytes - cmd->nleft;
                        if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
                                rq->resid_len += cmd->last_xfer_len;
                }
@@@ -737,7 -692,7 +691,7 @@@ static ide_startstop_t cdrom_start_rw(i
        struct request_queue *q = drive->queue;
        int write = rq_data_dir(rq) == WRITE;
        unsigned short sectors_per_frame =
 -              queue_hardsect_size(q) >> SECTOR_BITS;
 +              queue_logical_block_size(q) >> SECTOR_BITS;
  
        ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
                                  "secs_per_frame: %u",
@@@ -1021,8 -976,8 +975,8 @@@ int ide_cd_read_toc(ide_drive_t *drive
        /* save a private copy of the TOC capacity for error handling */
        drive->probed_capacity = toc->capacity * sectors_per_frame;
  
 -      blk_queue_hardsect_size(drive->queue,
 -                              sectors_per_frame << SECTOR_BITS);
 +      blk_queue_logical_block_size(drive->queue,
 +                                   sectors_per_frame << SECTOR_BITS);
  
        /* first read just the header, so we know how long the TOC is */
        stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
@@@ -1338,7 -1293,7 +1292,7 @@@ static int ide_cdrom_probe_capabilities
  /* standard prep_rq_fn that builds 10 byte cmds */
  static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
  {
 -      int hard_sect = queue_hardsect_size(q);
 +      int hard_sect = queue_logical_block_size(q);
        long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
        unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
  
@@@ -1543,7 -1498,7 +1497,7 @@@ static int ide_cdrom_setup(ide_drive_t 
  
        nslots = ide_cdrom_probe_capabilities(drive);
  
 -      blk_queue_hardsect_size(q, CD_FRAMESIZE);
 +      blk_queue_logical_block_size(q, CD_FRAMESIZE);
  
        if (ide_cdrom_register(drive, nslots)) {
                printk(KERN_ERR PFX "%s: %s failed to register device with the"
diff --combined drivers/ide/ide-tape.c
@@@ -240,27 -240,18 +240,27 @@@ static struct class *idetape_sysfs_clas
  
  static void ide_tape_release(struct device *);
  
 -static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
 +static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
 +
 +static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev,
 +                                       unsigned int i)
  {
        struct ide_tape_obj *tape = NULL;
  
        mutex_lock(&idetape_ref_mutex);
 -      tape = ide_drv_g(disk, ide_tape_obj);
 +
 +      if (cdev)
 +              tape = idetape_devs[i];
 +      else
 +              tape = ide_drv_g(disk, ide_tape_obj);
 +
        if (tape) {
                if (ide_device_get(tape->drive))
                        tape = NULL;
                else
                        get_device(&tape->dev);
        }
 +
        mutex_unlock(&idetape_ref_mutex);
        return tape;
  }
@@@ -275,14 -266,34 +275,16 @@@ static void ide_tape_put(struct ide_tap
        mutex_unlock(&idetape_ref_mutex);
  }
  
 -/*
 - * The variables below are used for the character device interface. Additional
 - * state variables are defined in our ide_drive_t structure.
 - */
 -static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
 -
 -static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
 -{
 -      struct ide_tape_obj *tape = NULL;
 -
 -      mutex_lock(&idetape_ref_mutex);
 -      tape = idetape_devs[i];
 -      if (tape)
 -              get_device(&tape->dev);
 -      mutex_unlock(&idetape_ref_mutex);
 -      return tape;
 -}
 -
  /*
   * called on each failed packet command retry to analyze the request sense. We
   * currently do not utilize this information.
   */
- static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
+ static void idetape_analyze_error(ide_drive_t *drive)
  {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc = drive->failed_pc;
+       struct request *rq = drive->hwif->rq;
+       u8 *sense = bio_data(rq->bio);
  
        tape->sense_key = sense[2] & 0xF;
        tape->asc       = sense[12];
        debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n",
                 pc->c[0], tape->sense_key, tape->asc, tape->ascq);
  
-       /* Correct pc->xferred by asking the tape.       */
+       /* correct remaining bytes to transfer */
        if (pc->flags & PC_FLAG_DMA_ERROR)
-               pc->xferred = pc->req_xfer -
-                       tape->blk_size *
-                       get_unaligned_be32(&sense[3]);
+               rq->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]);
  
        /*
         * If error was the result of a zero-length read or write command,
                        pc->flags |= PC_FLAG_ABORT;
                }
                if (!(pc->flags & PC_FLAG_ABORT) &&
-                   pc->xferred)
+                   (blk_rq_bytes(rq) - rq->resid_len))
                        pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
        }
  }
@@@ -354,12 -363,13 +354,13 @@@ static int ide_tape_callback(ide_drive_
  
        if (pc->c[0] == REQUEST_SENSE) {
                if (uptodate)
-                       idetape_analyze_error(drive, pc->buf);
+                       idetape_analyze_error(drive);
                else
                        printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
                                        "itself - Aborting request!\n");
        } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
-               int blocks = pc->xferred / tape->blk_size;
+               unsigned int blocks =
+                       (blk_rq_bytes(rq) - rq->resid_len) / tape->blk_size;
  
                tape->avg_size += blocks * tape->blk_size;
  
                }
  
                tape->first_frame += blocks;
-               rq->resid_len -= blocks * tape->blk_size;
  
                if (pc->error) {
                        uptodate = 0;
                        err = pc->error;
                }
-       } else if (pc->c[0] == READ_POSITION && uptodate) {
-               u8 *readpos = pc->buf;
-               debug_log(DBG_SENSE, "BOP - %s\n",
-                               (readpos[0] & 0x80) ? "Yes" : "No");
-               debug_log(DBG_SENSE, "EOP - %s\n",
-                               (readpos[0] & 0x40) ? "Yes" : "No");
-               if (readpos[0] & 0x4) {
-                       printk(KERN_INFO "ide-tape: Block location is unknown"
-                                        "to the tape\n");
-                       clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
-                                 &drive->atapi_flags);
-                       uptodate = 0;
-                       err = IDE_DRV_ERROR_GENERAL;
-               } else {
-                       debug_log(DBG_SENSE, "Block Location - %u\n",
-                                       be32_to_cpup((__be32 *)&readpos[4]));
-                       tape->partition = readpos[1];
-                       tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]);
-                       set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
-                               &drive->atapi_flags);
-               }
        }
        rq->errors = err;
  
        return uptodate;
@@@ -477,6 -461,7 +452,7 @@@ static ide_startstop_t ide_tape_issue_p
                                         struct ide_atapi_pc *pc)
  {
        idetape_tape_t *tape = drive->driver_data;
+       struct request *rq = drive->hwif->rq;
  
        if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
                drive->failed_pc = pc;
  
        if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
                (pc->flags & PC_FLAG_ABORT)) {
-               unsigned int done = blk_rq_bytes(drive->hwif->rq);
  
                /*
                 * We will "abort" retrying a packet command in case legitimate
  
                drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
-               ide_complete_rq(drive, -EIO, done);
+               ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
                return ide_stopped;
        }
        debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
@@@ -579,15 -563,13 +554,13 @@@ static void ide_tape_create_rw_cmd(idet
                                   struct ide_atapi_pc *pc, struct request *rq,
                                   u8 opcode)
  {
-       unsigned int length = blk_rq_sectors(rq);
+       unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9);
  
        ide_init_pc(pc);
        put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
-       pc->buf = NULL;
-       pc->buf_size = length * tape->blk_size;
-       pc->req_xfer = pc->buf_size;
-       if (pc->req_xfer == tape->buffer_size)
+       if (blk_rq_bytes(rq) == tape->buffer_size)
                pc->flags |= PC_FLAG_DMA_OK;
  
        if (opcode == READ_6)
@@@ -649,15 -631,15 +622,15 @@@ static ide_startstop_t idetape_do_reque
  
        if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
            (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
 -              set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
 +              drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
  
        if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
 -              set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
 +              drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
                drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
        }
  
 -      if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
 -          (stat & ATA_DSC) == 0) {
 +      if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) &&
 +          !(stat & ATA_DSC)) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_poll_freq = tape->best_dsc_rw_freq;
                        tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
                idetape_postpone_request(drive);
                return ide_stopped;
 -      }
 +      } else
 +              drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC;
 +
        if (rq->cmd[13] & REQ_IDETAPE_READ) {
                pc = &tape->queued_pc;
                ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
@@@ -713,7 -693,7 +686,7 @@@ out
  
        cmd.rq = rq;
  
-       ide_init_sg_cmd(&cmd, pc->req_xfer);
+       ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
        ide_map_sg(drive, &cmd);
  
        return ide_tape_issue_pc(drive, &cmd, pc);
@@@ -739,7 -719,7 +712,7 @@@ static int idetape_wait_ready(ide_drive
        int load_attempted = 0;
  
        /* Wait for the tape to become ready */
 -      set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
 +      set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags);
        timeout += jiffies;
        while (time_before(jiffies, timeout)) {
                if (ide_do_test_unit_ready(drive, disk) == 0)
@@@ -767,33 -747,51 +740,53 @@@ static int idetape_flush_tape_buffers(i
        int rc;
  
        idetape_create_write_filemark_cmd(drive, &pc, 0);
-       rc = ide_queue_pc_tail(drive, tape->disk, &pc);
+       rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0);
        if (rc)
                return rc;
        idetape_wait_ready(drive, 60 * 5 * HZ);
        return 0;
  }
  
- static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc)
- {
-       ide_init_pc(pc);
-       pc->c[0] = READ_POSITION;
-       pc->req_xfer = 20;
- }
- static int idetape_read_position(ide_drive_t *drive)
+ static int ide_tape_read_position(ide_drive_t *drive)
  {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc pc;
-       int position;
+       u8 buf[20];
  
        debug_log(DBG_PROCS, "Enter %s\n", __func__);
  
-       idetape_create_read_position_cmd(&pc);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc))
+       /* prep cmd */
+       ide_init_pc(&pc);
+       pc.c[0] = READ_POSITION;
+       pc.req_xfer = 20;
+       if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer))
                return -1;
-       position = tape->first_frame;
-       return position;
+       if (!pc.error) {
+               debug_log(DBG_SENSE, "BOP - %s\n",
+                               (buf[0] & 0x80) ? "Yes" : "No");
+               debug_log(DBG_SENSE, "EOP - %s\n",
+                               (buf[0] & 0x40) ? "Yes" : "No");
+               if (buf[0] & 0x4) {
+                       printk(KERN_INFO "ide-tape: Block location is unknown"
+                                        "to the tape\n");
 -                      clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
++                      clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
++                                &drive->atapi_flags);
+                       return -1;
+               } else {
+                       debug_log(DBG_SENSE, "Block Location - %u\n",
+                                       be32_to_cpup((__be32 *)&buf[4]));
+                       tape->partition = buf[1];
+                       tape->first_frame = be32_to_cpup((__be32 *)&buf[4]);
 -                      set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
++                      set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
++                              &drive->atapi_flags);
+               }
+       }
+       return tape->first_frame;
  }
  
  static void idetape_create_locate_cmd(ide_drive_t *drive,
@@@ -815,7 -813,7 +808,7 @@@ static void __ide_tape_discard_merge_bu
        if (tape->chrdev_dir != IDETAPE_DIR_READ)
                return;
  
 -      clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags);
 +      clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags);
        tape->valid = 0;
        if (tape->buf != NULL) {
                kfree(tape->buf);
@@@ -836,19 -834,21 +829,21 @@@ static int idetape_position_tape(ide_dr
  {
        idetape_tape_t *tape = drive->driver_data;
        struct gendisk *disk = tape->disk;
-       int retval;
+       int ret;
        struct ide_atapi_pc pc;
  
        if (tape->chrdev_dir == IDETAPE_DIR_READ)
                __ide_tape_discard_merge_buffer(drive);
        idetape_wait_ready(drive, 60 * 5 * HZ);
        idetape_create_locate_cmd(drive, &pc, block, partition, skip);
-       retval = ide_queue_pc_tail(drive, disk, &pc);
-       if (retval)
-               return (retval);
+       ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
+       if (ret)
+               return ret;
  
-       idetape_create_read_position_cmd(&pc);
-       return ide_queue_pc_tail(drive, disk, &pc);
+       ret = ide_tape_read_position(drive);
+       if (ret < 0)
+               return ret;
+       return 0;
  }
  
  static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
  
        __ide_tape_discard_merge_buffer(drive);
        if (restore_position) {
-               position = idetape_read_position(drive);
+               position = ide_tape_read_position(drive);
                seek = position > 0 ? position : 0;
                if (idetape_position_tape(drive, seek, 0, 0)) {
                        printk(KERN_INFO "ide-tape: %s: position_tape failed in"
@@@ -887,7 -887,6 +882,7 @@@ static int idetape_queue_rw_tail(ide_dr
        rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->cmd[13] = cmd;
        rq->rq_disk = tape->disk;
 +      rq->__sector = tape->first_frame;
  
        if (size) {
                ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size,
@@@ -1039,20 -1038,19 +1034,19 @@@ static int idetape_rewind_tape(ide_driv
  {
        struct ide_tape_obj *tape = drive->driver_data;
        struct gendisk *disk = tape->disk;
-       int retval;
        struct ide_atapi_pc pc;
+       int ret;
  
        debug_log(DBG_SENSE, "Enter %s\n", __func__);
  
        idetape_create_rewind_cmd(drive, &pc);
-       retval = ide_queue_pc_tail(drive, disk, &pc);
-       if (retval)
-               return retval;
+       ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
+       if (ret)
+               return ret;
  
-       idetape_create_read_position_cmd(&pc);
-       retval = ide_queue_pc_tail(drive, disk, &pc);
-       if (retval)
-               return retval;
+       ret = ide_tape_read_position(drive);
+       if (ret < 0)
+               return ret;
        return 0;
  }
  
@@@ -1108,8 -1106,7 +1102,8 @@@ static int idetape_space_over_filemarks
  
        if (tape->chrdev_dir == IDETAPE_DIR_READ) {
                tape->valid = 0;
 -              if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
 +              if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK),
 +                                     &drive->atapi_flags))
                        ++count;
                ide_tape_discard_merge_buffer(drive, 0);
        }
        case MTBSF:
                idetape_create_space_cmd(&pc, mt_count - count,
                                         IDETAPE_SPACE_OVER_FILEMARK);
-               return ide_queue_pc_tail(drive, disk, &pc);
+               return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
        case MTFSFM:
        case MTBSFM:
                if (!sprev)
@@@ -1164,7 -1161,7 +1158,7 @@@ static ssize_t idetape_chrdev_read(stru
        debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
  
        if (tape->chrdev_dir != IDETAPE_DIR_READ) {
 -              if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags))
 +              if (test_bit(ilog2(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;
                /* refill if staging buffer is empty */
                if (!tape->valid) {
                        /* If we are at a filemark, nothing more to read */
 -                      if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
 +                      if (test_bit(ilog2(IDE_AFLAG_FILEMARK),
 +                                   &drive->atapi_flags))
                                break;
                        /* read */
                        if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ,
                done += todo;
        }
  
 -      if (!done && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
 +      if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) {
                debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
  
                idetape_space_over_filemarks(drive, MTFSF, 1);
@@@ -1259,7 -1255,7 +1253,7 @@@ static int idetape_write_filemark(ide_d
  
        /* Write a filemark */
        idetape_create_write_filemark_cmd(drive, &pc, 1);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) {
                printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
                return -EIO;
        }
@@@ -1333,8 -1329,7 +1327,8 @@@ static int idetape_mtioctop(ide_drive_
                ide_tape_discard_merge_buffer(drive, 0);
                retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
                if (!retval)
 -                      clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
 +                      clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
 +                                &drive->atapi_flags);
                return retval;
        case MTNOP:
                ide_tape_discard_merge_buffer(drive, 0);
                        IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
        case MTEOM:
                idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
-               return ide_queue_pc_tail(drive, disk, &pc);
+               return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
        case MTERASE:
                (void)idetape_rewind_tape(drive);
                idetape_create_erase_cmd(&pc);
-               return ide_queue_pc_tail(drive, disk, &pc);
+               return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
        case MTSETBLK:
                if (mt_count) {
                        if (mt_count < tape->blk_size ||
                            mt_count % tape->blk_size)
                                return -EIO;
                        tape->user_bs_factor = mt_count / tape->blk_size;
 -                      clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
 +                      clear_bit(ilog2(IDE_AFLAG_DETECT_BS),
 +                                &drive->atapi_flags);
                } else
 -                      set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
 +                      set_bit(ilog2(IDE_AFLAG_DETECT_BS),
 +                              &drive->atapi_flags);
                return 0;
        case MTSEEK:
                ide_tape_discard_merge_buffer(drive, 0);
@@@ -1415,7 -1408,7 +1409,7 @@@ static int idetape_chrdev_ioctl(struct 
        if (cmd == MTIOCGET || cmd == MTIOCPOS) {
                block_offset = tape->valid /
                        (tape->blk_size * tape->user_bs_factor);
-               position = idetape_read_position(drive);
+               position = ide_tape_read_position(drive);
                if (position < 0)
                        return -EIO;
        }
@@@ -1458,9 -1451,10 +1452,10 @@@ static void ide_tape_get_bsize_from_bde
  {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc pc;
+       u8 buf[12];
  
        idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) {
                printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
                if (tape->blk_size == 0) {
                        printk(KERN_WARNING "ide-tape: Cannot deal with zero "
                }
                return;
        }
-       tape->blk_size = (pc.buf[4 + 5] << 16) +
-                               (pc.buf[4 + 6] << 8)  +
-                                pc.buf[4 + 7];
-       tape->drv_write_prot = (pc.buf[2] & 0x80) >> 7;
+       tape->blk_size = (buf[4 + 5] << 16) +
+                               (buf[4 + 6] << 8)  +
+                                buf[4 + 7];
+       tape->drv_write_prot = (buf[2] & 0x80) >> 7;
  }
  
  static int idetape_chrdev_open(struct inode *inode, struct file *filp)
                return -ENXIO;
  
        lock_kernel();
 -      tape = ide_tape_chrdev_get(i);
 +      tape = ide_tape_get(NULL, true, i);
        if (!tape) {
                unlock_kernel();
                return -ENXIO;
  
        filp->private_data = tape;
  
 -      if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) {
 +      if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) {
                retval = -EBUSY;
                goto out_put_tape;
        }
  
        retval = idetape_wait_ready(drive, 60 * HZ);
        if (retval) {
 -              clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
 +              clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
                printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
                goto out_put_tape;
        }
  
 -      ide_tape_read_position(drive);
 -      if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags))
 +      idetape_read_position(drive);
 +      if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags))
                (void)idetape_rewind_tape(drive);
  
        /* Read block size and write protect status from drive. */
        if (tape->write_prot) {
                if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
                    (filp->f_flags & O_ACCMODE) == O_RDWR) {
 -                      clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
 +                      clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
                        retval = -EROFS;
                        goto out_put_tape;
                }
@@@ -1591,17 -1585,15 +1586,17 @@@ static int idetape_chrdev_release(struc
                        ide_tape_discard_merge_buffer(drive, 1);
        }
  
 -      if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags))
 +      if (minor < 128 && test_bit(ilog2(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) {
                        if (!ide_set_media_lock(drive, tape->disk, 0))
                                tape->door_locked = DOOR_UNLOCKED;
                }
        }
 -      clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
 +      clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
        ide_tape_put(tape);
        unlock_kernel();
        return 0;
@@@ -1615,17 -1607,14 +1610,14 @@@ static void idetape_get_inquiry_results
        char fw_rev[4], vendor_id[8], product_id[16];
  
        idetape_create_inquiry_cmd(&pc);
-       pc.buf = &pc_buf[0];
-       pc.buf_size = sizeof(pc_buf);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) {
                printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
                                tape->name);
                return;
        }
-       memcpy(vendor_id, &pc.buf[8], 8);
-       memcpy(product_id, &pc.buf[16], 16);
-       memcpy(fw_rev, &pc.buf[32], 4);
+       memcpy(vendor_id, &pc_buf[8], 8);
+       memcpy(product_id, &pc_buf[16], 16);
+       memcpy(fw_rev, &pc_buf[32], 4);
  
        ide_fixstring(vendor_id, 8, 0);
        ide_fixstring(product_id, 16, 0);
@@@ -1643,11 -1632,11 +1635,11 @@@ static void idetape_get_mode_sense_resu
  {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc pc;
-       u8 *caps;
+       u8 buf[24], *caps;
        u8 speed, max_speed;
  
        idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) {
                printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
                                " some default values\n");
                tape->blk_size = 512;
                put_unaligned(6*52, (u16 *)&tape->caps[16]);
                return;
        }
-       caps = pc.buf + 4 + pc.buf[3];
+       caps = buf + 4 + buf[3];
  
        /* convert to host order and save for later use */
        speed = be16_to_cpup((__be16 *)&caps[14]);
@@@ -1907,7 -1896,7 +1899,7 @@@ static const struct file_operations ide
  
  static int idetape_open(struct block_device *bdev, fmode_t mode)
  {
 -      struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk);
 +      struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk, false, 0);
  
        if (!tape)
                return -ENXIO;
diff --combined include/linux/ide.h
@@@ -178,7 -178,7 +178,7 @@@ typedef u8 hwif_chipset_t
  /*
   * Structure to hold all information about the location of this port
   */
 -typedef struct hw_regs_s {
 +struct ide_hw {
        union {
                struct ide_io_ports     io_ports;
                unsigned long           io_ports_array[IDE_NR_PORTS];
  
        int             irq;                    /* our irq number */
        ide_ack_intr_t  *ack_intr;              /* acknowledge interrupt */
 -      hwif_chipset_t  chipset;
        struct device   *dev, *parent;
        unsigned long   config;
 -} hw_regs_t;
 +};
  
 -static inline void ide_std_init_ports(hw_regs_t *hw,
 +static inline void ide_std_init_ports(struct ide_hw *hw,
                                      unsigned long io_addr,
                                      unsigned long ctl_addr)
  {
  
  /*
   * Special Driver Flags
 - *
 - * set_geometry       : respecify drive geometry
 - * recalibrate        : seek to cyl 0
 - * set_multmode       : set multmode count
 - * reserved   : unused
   */
 -typedef union {
 -      unsigned all                    : 8;
 -      struct {
 -              unsigned set_geometry   : 1;
 -              unsigned recalibrate    : 1;
 -              unsigned set_multmode   : 1;
 -              unsigned reserved       : 5;
 -      } b;
 -} special_t;
 +enum {
 +      IDE_SFLAG_SET_GEOMETRY          = (1 << 0),
 +      IDE_SFLAG_RECALIBRATE           = (1 << 1),
 +      IDE_SFLAG_SET_MULTMODE          = (1 << 2),
 +};
  
  /*
   * Status returned from various ide_ functions
@@@ -331,11 -341,6 +331,6 @@@ enum 
        PC_FLAG_WRITING                 = (1 << 6),
  };
  
- /*
-  * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes.
-  * This is used for several packet commands (not for READ/WRITE commands).
-  */
- #define IDE_PC_BUFFER_SIZE    64
  #define ATAPI_WAIT_PC         (60 * HZ)
  
  struct ide_atapi_pc {
  
        /* bytes to transfer */
        int req_xfer;
-       /* bytes actually transferred */
-       int xferred;
-       /* data buffer */
-       u8 *buf;
-       int buf_size;
  
        /* the corresponding request */
        struct request *rq;
         * those are more or less driver-specific and some of them are subject
         * to change/removal later.
         */
-       u8 pc_buf[IDE_PC_BUFFER_SIZE];
        unsigned long timeout;
  };
  
@@@ -381,7 -378,6 +368,7 @@@ struct ide_drive_s
  struct ide_disk_ops {
        int             (*check)(struct ide_drive_s *, const char *);
        int             (*get_capacity)(struct ide_drive_s *);
 +      u64             (*set_capacity)(struct ide_drive_s *, u64);
        void            (*setup)(struct ide_drive_s *);
        void            (*flush)(struct ide_drive_s *);
        int             (*init_media)(struct ide_drive_s *, struct gendisk *);
@@@ -459,8 -455,6 +446,8 @@@ enum 
        IDE_DFLAG_NICE1                 = (1 << 5),
        /* device is physically present */
        IDE_DFLAG_PRESENT               = (1 << 6),
 +      /* disable Host Protected Area */
 +      IDE_DFLAG_NOHPA                 = (1 << 7),
        /* id read from device (synthetic if not set) */
        IDE_DFLAG_ID_READ               = (1 << 8),
        IDE_DFLAG_NOPROBE               = (1 << 9),
        /* write protect */
        IDE_DFLAG_WP                    = (1 << 29),
        IDE_DFLAG_FORMAT_IN_PROGRESS    = (1 << 30),
 +      IDE_DFLAG_NIEN_QUIRK            = (1 << 31),
  };
  
  struct ide_drive_s {
        unsigned long sleep;            /* sleep until this time */
        unsigned long timeout;          /* max time to wait for irq */
  
 -      special_t       special;        /* special action flags */
 +      u8      special_flags;          /* special action flags */
  
        u8      select;                 /* basic drive/head select reg value */
        u8      retry_pio;              /* retrying dma capable host in pio */
        u8      waiting_for_dma;        /* dma currently in progress */
        u8      dma;                    /* atapi dma flag */
  
 -        u8    quirk_list;     /* considered quirky, set for a specific host */
          u8    init_speed;     /* transfer rate set at boot */
          u8    current_speed;  /* current transfer rate set */
        u8      desired_speed;  /* desired transfer rate set */
        unsigned int    drive_data;     /* used by set_pio_mode/dev_select() */
        unsigned int    failures;       /* current failure count */
        unsigned int    max_failures;   /* maximum allowed failure count */
 -      u64             probed_capacity;/* initial reported media capacity (ide-cd only currently) */
 -
 +      u64             probed_capacity;/* initial/native media capacity */
        u64             capacity64;     /* total number of sectors */
  
        int             lun;            /* logical unit */
@@@ -1095,7 -1090,7 +1082,7 @@@ void ide_fix_driveid(u16 *)
  
  extern void ide_fixstring(u8 *, const int, const int);
  
 -int ide_busy_sleep(ide_hwif_t *, unsigned long, int);
 +int ide_busy_sleep(ide_drive_t *, unsigned long, int);
  
  int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
  
@@@ -1130,6 -1125,8 +1117,8 @@@ void SELECT_MASK(ide_drive_t *, int)
  u8 ide_read_error(ide_drive_t *);
  void ide_read_bcount_and_ireason(ide_drive_t *, u16 *, u8 *);
  
+ int ide_check_ireason(ide_drive_t *, struct request *, int, int, int);
  int ide_check_atapi_device(ide_drive_t *, const char *);
  
  void ide_init_pc(struct ide_atapi_pc *);
@@@ -1154,7 -1151,8 +1143,8 @@@ enum 
        REQ_IDETAPE_WRITE       = (1 << 3),
  };
  
- int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *);
+ int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *,
+                     void *, unsigned int);
  
  int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *);
  int ide_do_start_stop(ide_drive_t *, struct gendisk *, int);
@@@ -1214,7 -1212,7 +1204,7 @@@ static inline int ide_pci_is_in_compati
  }
  
  void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *,
 -                       hw_regs_t *, hw_regs_t **);
 +                       struct ide_hw *, struct ide_hw **);
  void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
  
  #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@@ -1453,18 -1451,16 +1443,18 @@@ static inline void ide_acpi_set_state(i
  void ide_register_region(struct gendisk *);
  void ide_unregister_region(struct gendisk *);
  
 +void ide_check_nien_quirk_list(ide_drive_t *);
  void ide_undecoded_slave(ide_drive_t *);
  
  void ide_port_apply_params(ide_hwif_t *);
  int ide_sysfs_register_port(ide_hwif_t *);
  
 -struct ide_host *ide_host_alloc(const struct ide_port_info *, hw_regs_t **);
 +struct ide_host *ide_host_alloc(const struct ide_port_info *, struct ide_hw **,
 +                              unsigned int);
  void ide_host_free(struct ide_host *);
  int ide_host_register(struct ide_host *, const struct ide_port_info *,
 -                    hw_regs_t **);
 -int ide_host_add(const struct ide_port_info *, hw_regs_t **,
 +                    struct ide_hw **);
 +int ide_host_add(const struct ide_port_info *, struct ide_hw **, unsigned int,
                 struct ide_host **);
  void ide_host_remove(struct ide_host *);
  int ide_legacy_device_add(const struct ide_port_info *, unsigned long);