diff options
Diffstat (limited to 'drivers/block/ide-tape.c')
-rw-r--r-- | drivers/block/ide-tape.c | 141 |
1 files changed, 63 insertions, 78 deletions
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index e9d7f1433..a30fc9a58 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.11 - BETA Dec 2, 1996 + * linux/drivers/block/ide-tape.c Version 1.12 Dec 7, 1997 * * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il> * @@ -206,6 +206,11 @@ * Use ide_stall_queue() for DSC overlap. * Use the maximum speed rather than the current speed * to compute the request service time. + * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data + * corruption, which could occur if the total number + * of bytes written to the tape was not an integral + * number of tape blocks. + * Add support for INTERRUPT DRQ devices. * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -315,6 +320,8 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ +#define IDETAPE_VERSION "1.12" + #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -323,12 +330,9 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/major.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/malloc.h> @@ -692,6 +696,7 @@ typedef struct { #define IDETAPE_PIPELINE_ERROR 3 /* Error detected in a pipeline stage */ #define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */ #define IDETAPE_FILEMARK 5 /* Currently on a filemark */ +#define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */ /* * Supported ATAPI tape drives packet commands @@ -1152,11 +1157,6 @@ static void idetape_postpone_request (ide_drive_t *drive) */ static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq) { - unsigned int major = HWIF(drive)->major; - struct blk_dev_struct *bdev = &blk_dev[major]; - - bdev->current_request=HWGROUP (drive)->rq; /* Since we may have taken it out */ - ide_init_drive_cmd (rq); rq->buffer = (char *) pc; rq->cmd = IDETAPE_PC_RQ1; @@ -1542,16 +1542,12 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup) ide_drive_t *drive = hwgroup->drive; struct request *rq = hwgroup->rq; idetape_tape_t *tape = drive->driver_data; - unsigned int major = HWIF(drive)->major; - struct blk_dev_struct *bdev = &blk_dev[major]; int error; #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_end_request\n"); #endif /* IDETAPE_DEBUG_LOG */ - bdev->current_request=rq; /* Since we may have taken it out */ - switch (uptodate) { case 0: error = IDETAPE_ERROR_GENERAL; break; case 1: error = 0; break; @@ -1723,18 +1719,23 @@ static void idetape_pc_intr (ide_drive_t *drive) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { - if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) { - set_bit (PC_DMA_ERROR, &pc->flags); + if (HWIF(drive)->dmaproc(ide_dma_end, drive)) { /* - * We will currently correct the following in - * idetape_analyze_error. + * A DMA error is sometimes expected. For example, + * if the tape is crossing a filemark during a + * READ command, it will issue an irq and position + * itself before the filemark, so that only a partial + * data transfer will occur (which causes the DMA + * error). In that case, we will later ask the tape + * how much bytes of the original request were + * actually transferred (we can't receive that + * information from the DMA engine on most chipsets). */ - pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive); + set_bit (PC_DMA_ERROR, &pc->flags); } else { pc->actually_transferred=pc->request_transfer; idetape_update_buffers (pc); } - (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */ #if IDETAPE_DEBUG_LOG printk (KERN_INFO "ide-tape: DMA finished\n"); #endif /* IDETAPE_DEBUG_LOG */ @@ -1780,7 +1781,7 @@ static void idetape_pc_intr (ide_drive_t *drive) if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n"); printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); ide_do_reset (drive); return; } @@ -1873,11 +1874,31 @@ static void idetape_pc_intr (ide_drive_t *drive) * we will handle the next request. * */ + +static void idetape_transfer_pc(ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t *pc = tape->pc; + idetape_ireason_reg_t ireason; + + if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); + return; + } + ireason.all=IN_BYTE (IDE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { + printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); + ide_do_reset (drive); + return; + } + ide_set_handler(drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */ + atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ +} + static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) { idetape_tape_t *tape = drive->driver_data; idetape_bcount_reg_t bcount; - idetape_ireason_reg_t ireason; int dma_ok=0; #if IDETAPE_DEBUG_BUGS @@ -1918,7 +1939,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n"); - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); } if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); @@ -1929,35 +1950,19 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); OUT_BYTE (drive->select.all,IDE_SELECT_REG); - - ide_set_handler (drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */ - OUT_BYTE (WIN_PACKETCMD,IDE_COMMAND_REG); /* Issue the packet command */ - - if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { /* Wait for DRQ to be ready - Assuming Accelerated DRQ */ - /* - * We currently only support tape drives which report - * accelerated DRQ assertion. For this case, specs - * allow up to 50us. We really shouldn't get here. - * - * ??? Still needs to think what to do if we reach - * here anyway. - */ - printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); - return; - } - ireason.all=IN_BYTE (IDE_IREASON_REG); - if (!ireason.b.cod || ireason.b.io) { - printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); - ide_do_reset (drive); - return; - } - atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ #ifdef CONFIG_BLK_DEV_IDEDMA if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } #endif /* CONFIG_BLK_DEV_IDEDMA */ + if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { + ide_set_handler(drive, &idetape_transfer_pc, WAIT_CMD); + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + } else { + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + idetape_transfer_pc(drive); + } } static void idetape_media_access_finished (ide_drive_t *drive) @@ -2179,7 +2184,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; - struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major]; struct request *postponed_rq = tape->postponed_rq; idetape_status_reg_t status; @@ -2198,32 +2202,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned } /* - * This is an important point. We will try to remove our request - * from the block device request queue while we service the - * request. Note that the request must be returned to - * bdev->current_request before the next call to - * ide_end_drive_cmd or ide_do_drive_cmd to conform with the - * normal behavior of the IDE driver, which leaves the active - * request in bdev->current_request during I/O. - * - * This will eliminate fragmentation of disk/cdrom requests - * around a tape request, now that we are using ide_next to - * insert pending pipeline requests, since we have only one - * ide-tape.c data request in the device request queue, and - * thus once removed, ll_rw_blk.c will only see requests from - * the other device. - * - * The potential fragmentation inefficiency was pointed to me - * by Mark Lord. - * - * Uhuh.. the following "fix" is actually not entirely correct. - * Some day we should probably move to a per device request - * queue, rather than per interface. - */ - if (rq->next != NULL && rq->rq_dev != rq->next->rq_dev) - bdev->current_request=rq->next; - - /* * Retry a failed packet command */ if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { @@ -2612,8 +2590,8 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive) if (tape->merge_stage_size % tape->tape_block_size) { blocks++; i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; - memset (tape->merge_stage->bh->b_data + tape->merge_stage->bh->b_count, 0, i); - tape->merge_stage->bh->b_count += i; + memset (tape->bh->b_data + tape->bh->b_count, 0, i); + tape->bh->b_count += i; } (void) idetape_add_chrdev_write_request (drive, blocks); tape->merge_stage_size = 0; @@ -3378,9 +3356,9 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) case 1: printk (KERN_INFO "16 bytes\n");break; default: printk (KERN_INFO "Reserved\n");break; } - printk (KERN_INFO "Model: %s\n",id->model); - printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev); - printk (KERN_INFO "Serial Number: %s\n",id->serial_no); + printk (KERN_INFO "Model: %.40s\n",id->model); + printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev); + printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no); printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512); printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); @@ -3532,6 +3510,7 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) ide_hwif_t *hwif = HWIF(drive); unsigned long t1, tmid, tn, t; u16 speed; + struct idetape_id_gcw gcw; drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ @@ -3543,6 +3522,9 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->chrdev_direction = idetape_direction_none; tape->pc = tape->pc_stack; tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + *((unsigned short *) &gcw) = drive->id->config; + if (gcw.drq_type == 1) + set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); idetape_get_mode_sense_results (drive); @@ -3635,6 +3617,8 @@ static ide_module_t idetape_module = { * IDE subdriver functions, registered with ide.c */ static ide_driver_t idetape_driver = { + "ide-tape", /* name */ + IDETAPE_VERSION, /* version */ ide_tape, /* media */ 1, /* busy */ 1, /* supports_dma */ @@ -3648,7 +3632,8 @@ static ide_driver_t idetape_driver = { NULL, /* media_change */ idetape_pre_reset, /* pre_reset */ NULL, /* capacity */ - NULL /* special */ + NULL, /* special */ + NULL /* proc */ }; /* |