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.
+                */
+               if (!blk_special_request(rq) &&
+                   (drive->media == ide_tape && !rq->bio))
+                       done = ide_rq_bytes(rq);        /* FIXME */
+               else
+                       done = blk_rq_bytes(rq);
+
                /* Command finished - Call the callback function */
                uptodate = drive->pc_callback(drive, dsc);
 
 
                if (blk_special_request(rq)) {
                        rq->errors = 0;
-                       done = blk_rq_bytes(rq);
                        error = 0;
                } else {
 
                                        rq->errors = -EIO;
                        }
 
-                       if (drive->media == ide_tape && !rq->bio)
-                               done = ide_rq_bytes(rq); /* FIXME */
-                       else
-                               done = blk_rq_bytes(rq);
-
                        error = uptodate ? 0 : -EIO;
                }
 
 
        drive->pc = pc;
 
        if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
+               unsigned int done = blk_rq_bytes(drive->hwif->rq);
+
                if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
                        ide_floppy_report_error(floppy, pc);
+
                /* Giving up */
                pc->error = IDE_DRV_ERROR_GENERAL;
 
                drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
-               ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq));
+               ide_complete_rq(drive, -EIO, done);
                return ide_stopped;
        }
 
 
 
        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
                 * error code was received (crossing a filemark, or end of the
                        /* Giving up */
                        pc->error = IDE_DRV_ERROR_GENERAL;
                }
+
                drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
-               ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq));
+               ide_complete_rq(drive, -EIO, done);
                return ide_stopped;
        }
        debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);