return 1;
}
-/*
- * Interrupt routine. Called when a read request has completed.
- */
-static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
-{
- int stat;
- int ireason, len, sectors_to_transfer, nskip;
- struct cdrom_info *info = drive->driver_data;
- u8 lowcyl = 0, highcyl = 0;
- int dma = info->dma, dma_error = 0;
-
- struct request *rq = HWGROUP(drive)->rq;
-
- /*
- * handle dma case
- */
- if (dma) {
- info->dma = 0;
- dma_error = HWIF(drive)->ide_dma_end(drive);
- if (dma_error) {
- printk(KERN_ERR "%s: DMA read error\n", drive->name);
- ide_dma_off(drive);
- }
- }
-
- if (cdrom_decode_status(drive, 0, &stat))
- return ide_stopped;
-
- if (dma) {
- if (!dma_error) {
- ide_end_request(drive, 1, rq->nr_sectors);
- return ide_stopped;
- } else
- return ide_error(drive, "dma error", stat);
- }
-
- /* Read the interrupt reason and the transfer length. */
- ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
- lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG);
- highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-
- len = lowcyl + (256 * highcyl);
-
- /* If DRQ is clear, the command has completed. */
- if ((stat & DRQ_STAT) == 0) {
- /* If we're not done filling the current buffer, complain.
- Otherwise, complete the command normally. */
- if (rq->current_nr_sectors > 0) {
- printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
- drive->name, rq->current_nr_sectors);
- rq->cmd_flags |= REQ_FAILED;
- cdrom_end_request(drive, 0);
- } else
- cdrom_end_request(drive, 1);
- return ide_stopped;
- }
-
- /* Check that the drive is expecting to do the same thing we are. */
- if (cdrom_read_check_ireason (drive, len, ireason))
- return ide_stopped;
-
- if (ide_cd_check_transfer_size(drive, len)) {
- cdrom_end_request(drive, 0);
- return ide_stopped;
- }
-
- /* The number of sectors we need to read from the drive. */
- sectors_to_transfer = len / SECTOR_SIZE;
-
- /* First, figure out if we need to bit-bucket
- any of the leading sectors. */
- nskip = min_t(int, rq->current_nr_sectors - bio_cur_sectors(rq->bio), sectors_to_transfer);
-
- if (nskip > 0) {
- ide_cd_drain_data(drive, nskip);
- rq->current_nr_sectors -= nskip;
- sectors_to_transfer -= nskip;
- }
-
- /* Now loop while we still have data to read from the drive. */
- while (sectors_to_transfer > 0) {
- int this_transfer;
-
- /* If we've filled the present buffer but there's another
- chained buffer after it, move on. */
- if (rq->current_nr_sectors == 0 && rq->nr_sectors)
- cdrom_end_request(drive, 1);
-
- /* If the buffers are full, cache the rest of the data in our
- internal buffer. */
- if (rq->current_nr_sectors == 0) {
- cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer);
- sectors_to_transfer = 0;
- } else {
- /* Transfer data to the buffers.
- Figure out how many sectors we can transfer
- to the current buffer. */
- this_transfer = min_t(int, sectors_to_transfer,
- rq->current_nr_sectors);
-
- /* Read this_transfer sectors
- into the current buffer. */
- while (this_transfer > 0) {
- HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
- rq->buffer += SECTOR_SIZE;
- --rq->nr_sectors;
- --rq->current_nr_sectors;
- ++rq->sector;
- --this_transfer;
- --sectors_to_transfer;
- }
- }
- }
-
- /* Done moving data! Wait for another interrupt. */
- ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL);
- return ide_started;
-}
-
/*
* Try to satisfy some of the current read request from our cached data.
* Returns nonzero if the request has been completed, zero otherwise.
return 0;
}
+static ide_startstop_t cdrom_rw_intr(ide_drive_t *);
+
/*
* Routine to send a read packet command to the drive.
* This is usually called directly from cdrom_start_read.
rq->timeout = ATAPI_WAIT_PC;
/* Send the command to the drive and return. */
- return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr);
+ return cdrom_transfer_packet_command(drive, rq, cdrom_rw_intr);
}
/*
* best way to deal with dma that is not sector aligned right now... note
* that in this path we are not using ->data or ->buffer at all. this irs
- * can replace cdrom_read_intr() and cdrom_write_intr() in the future.
+ * can replace cdrom_rw_intr() in the future.
*/
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
return ide_stopped;
}
-static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
+static ide_startstop_t cdrom_rw_intr(ide_drive_t *drive)
{
- int stat, ireason, len, sectors_to_transfer, uptodate;
struct cdrom_info *info = drive->driver_data;
- int dma_error = 0, dma = info->dma;
- u8 lowcyl = 0, highcyl = 0;
-
struct request *rq = HWGROUP(drive)->rq;
+ xfer_func_t *xferfunc;
+ int stat, ireason, len, sectors_to_transfer, uptodate, nskip;
+ int dma_error = 0, dma = info->dma, write = rq_data_dir(rq) == WRITE;
+ u8 lowcyl = 0, highcyl = 0;
/* Check for errors. */
if (dma) {
info->dma = 0;
dma_error = HWIF(drive)->ide_dma_end(drive);
if (dma_error) {
- printk(KERN_ERR "%s: DMA write error\n", drive->name);
+ printk(KERN_ERR "%s: DMA %s error\n", drive->name,
+ write ? "write" : "read");
ide_dma_off(drive);
}
}
/* If DRQ is clear, the command has completed. */
if ((stat & DRQ_STAT) == 0) {
- /* If we're not done writing, complain.
+ /*
+ * If we're not done reading/writing, complain.
* Otherwise, complete the command normally.
*/
uptodate = 1;
printk(KERN_ERR "%s: %s: data underrun (%d blocks)\n",
drive->name, __FUNCTION__,
rq->current_nr_sectors);
+ if (!write)
+ rq->cmd_flags |= REQ_FAILED;
uptodate = 0;
}
cdrom_end_request(drive, uptodate);
return ide_stopped;
}
+ sectors_to_transfer = len / SECTOR_SIZE;
+
/* Check that the drive is expecting to do the same thing we are. */
- if (cdrom_write_check_ireason(drive, len, ireason))
- return ide_stopped;
+ if (write) {
+ if (cdrom_write_check_ireason(drive, len, ireason))
+ return ide_stopped;
- sectors_to_transfer = len / SECTOR_SIZE;
+ xferfunc = HWIF(drive)->atapi_output_bytes;
+ } else {
+ if (cdrom_read_check_ireason(drive, len, ireason))
+ return ide_stopped;
+
+ if (ide_cd_check_transfer_size(drive, len)) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ /*
+ * First, figure out if we need to bit-bucket
+ * any of the leading sectors.
+ */
+ nskip = min_t(int, rq->current_nr_sectors
+ - bio_cur_sectors(rq->bio),
+ sectors_to_transfer);
+
+ if (nskip > 0) {
+ ide_cd_drain_data(drive, nskip);
+ rq->current_nr_sectors -= nskip;
+ sectors_to_transfer -= nskip;
+ }
+
+ xferfunc = HWIF(drive)->atapi_input_bytes;
+ }
/*
- * now loop and write out the data
+ * now loop and read/write the data
*/
while (sectors_to_transfer > 0) {
int this_transfer;
+ /*
+ * If we've filled the present buffer but there's another
+ * chained buffer after it, move on.
+ */
+ if (!write && rq->current_nr_sectors == 0 && rq->nr_sectors)
+ cdrom_end_request(drive, 1);
+
if (!rq->current_nr_sectors) {
- printk(KERN_ERR "%s: %s: confused, missing data\n",
- drive->name, __FUNCTION__);
+ if (!write)
+ /*
+ * If the buffers are full, cache the rest
+ * of the data in our internal buffer.
+ */
+ cdrom_buffer_sectors(drive, rq->sector,
+ sectors_to_transfer);
+ else
+ printk(KERN_ERR "%s: %s: confused, missing "
+ "data\n",
+ drive->name, __FUNCTION__);
break;
}
this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors);
while (this_transfer > 0) {
- HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+ xferfunc(drive, rq->buffer, SECTOR_SIZE);
rq->buffer += SECTOR_SIZE;
--rq->nr_sectors;
--rq->current_nr_sectors;
/*
* current buffer complete, move on
*/
- if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+ if (write && rq->current_nr_sectors == 0 && rq->nr_sectors)
cdrom_end_request(drive, 1);
}
/* re-arm handler */
- ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL);
+ ide_set_handler(drive, cdrom_rw_intr, ATAPI_WAIT_PC, NULL);
return ide_started;
}
#endif
rq->timeout = ATAPI_WAIT_PC;
- return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);
+ return cdrom_transfer_packet_command(drive, rq, cdrom_rw_intr);
}
static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)