Commit 9a11cf9e authored by Alan Stern's avatar Alan Stern Committed by Linus Torvalds

[PATCH] ide-tape driver update

Here is my multiple-bug-fix patch for the ide-tape driver.

The corresponding patch for 2.4.21 has already been accepted by Marcelo.
parent 10511488
/* /*
* linux/drivers/ide/ide-tape.c Version 1.17a Jan, 2001 * linux/drivers/ide/ide-tape.c Version 1.17b Oct, 2002
* *
* Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il> * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
* *
...@@ -291,6 +291,28 @@ ...@@ -291,6 +291,28 @@
* Ver 1.17a Apr 2001 Willem Riede osst@riede.org * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
* - Get drive's actual block size from mode sense block descriptor * - Get drive's actual block size from mode sense block descriptor
* - Limit size of pipeline * - Limit size of pipeline
* Ver 1.17b Oct 2002 Alan Stern <stern@rowland.harvard.edu>
* Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
* it in the code!
* Actually removed aborted stages in idetape_abort_pipeline
* instead of just changing the command code.
* Made the transfer byte count for Request Sense equal to the
* actual length of the data transfer.
* Changed handling of partial data transfers: they do not
* cause DMA errors.
* Moved initiation of DMA transfers to the correct place.
* Removed reference to unallocated memory.
* Made __idetape_discard_read_pipeline return the number of
* sectors skipped, not the number of stages.
* Replaced errant kfree() calls with __idetape_kfree_stage().
* Fixed off-by-one error in testing the pipeline length.
* Fixed handling of filemarks in the read pipeline.
* Small code optimization for MTBSF and MTBSFM ioctls.
* Don't try to unlock the door during device close if is
* already unlocked!
* Cosmetic fixes to miscellaneous debugging output messages.
* Set the minimum /proc/ide/hd?/settings values for "pipeline",
* "pipeline_min", and "pipeline_max" to 1.
* *
* Here are some words from the first releases of hd.c, which are quoted * Here are some words from the first releases of hd.c, which are quoted
* in ide.c and apply here as well: * in ide.c and apply here as well:
...@@ -400,7 +422,7 @@ ...@@ -400,7 +422,7 @@
* sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
*/ */
#define IDETAPE_VERSION "1.17a" #define IDETAPE_VERSION "1.17b"
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -577,9 +599,10 @@ typedef struct { ...@@ -577,9 +599,10 @@ typedef struct {
* whenever we sense that the pipeline is empty, until we reach * whenever we sense that the pipeline is empty, until we reach
* the optimum value or until we reach MAX. * the optimum value or until we reach MAX.
* *
* Setting the following parameter to 0 will disable the pipelined mode. * Setting the following parameter to 0 is illegal: the pipelined mode
* cannot be disabled (calculate_speeds() divides by tape->max_stages.)
*/ */
#define IDETAPE_MIN_PIPELINE_STAGES 200 #define IDETAPE_MIN_PIPELINE_STAGES 1
#define IDETAPE_MAX_PIPELINE_STAGES 400 #define IDETAPE_MAX_PIPELINE_STAGES 400
#define IDETAPE_INCREASE_STAGES_RATE 20 #define IDETAPE_INCREASE_STAGES_RATE 20
...@@ -601,8 +624,8 @@ typedef struct { ...@@ -601,8 +624,8 @@ typedef struct {
* is verified to be stable enough. This will make it much more * is verified to be stable enough. This will make it much more
* esthetic. * esthetic.
*/ */
#define IDETAPE_DEBUG_INFO 1 #define IDETAPE_DEBUG_INFO 0
#define IDETAPE_DEBUG_LOG 1 #define IDETAPE_DEBUG_LOG 0
#define IDETAPE_DEBUG_LOG_VERBOSE 0 #define IDETAPE_DEBUG_LOG_VERBOSE 0
#define IDETAPE_DEBUG_BUGS 1 #define IDETAPE_DEBUG_BUGS 1
...@@ -1610,24 +1633,6 @@ static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_res ...@@ -1610,24 +1633,6 @@ static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_res
} }
} }
static void idetape_abort_pipeline (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage = tape->next_stage;
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 4)
printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
#endif
while (stage) {
if (stage->rq.flags == IDETAPE_WRITE_RQ)
stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ;
else if (stage->rq.flags == IDETAPE_READ_RQ)
stage->rq.flags = IDETAPE_ABORTED_READ_RQ;
stage = stage->next;
}
}
/* /*
* idetape_active_next_stage will declare the next stage as "active". * idetape_active_next_stage will declare the next stage as "active".
*/ */
...@@ -1672,7 +1677,7 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive) ...@@ -1672,7 +1677,7 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n"); printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
#endif /* IDETAPE_DEBUG_LOG */ #endif /* IDETAPE_DEBUG_LOG */
tape->max_stages += increase; tape->max_stages += max(increase, 1);
tape->max_stages = max(tape->max_stages, tape->min_pipeline); tape->max_stages = max(tape->max_stages, tape->min_pipeline);
tape->max_stages = min(tape->max_stages, tape->max_pipeline); tape->max_stages = min(tape->max_stages, tape->max_pipeline);
} }
...@@ -1745,6 +1750,29 @@ static void idetape_remove_stage_head (ide_drive_t *drive) ...@@ -1745,6 +1750,29 @@ static void idetape_remove_stage_head (ide_drive_t *drive)
} }
} }
static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage = tape->next_stage;
idetape_stage_t *nstage;
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 4)
printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
#endif
while (stage) {
nstage = stage->next;
idetape_kfree_stage(tape, stage);
--tape->nr_stages;
--tape->nr_pending_stages;
stage = nstage;
}
tape->last_stage = last_stage;
if (last_stage)
last_stage->next = NULL;
tape->next_stage = NULL;
}
/* /*
* idetape_end_request is used to finish servicing a request, and to * idetape_end_request is used to finish servicing a request, and to
* insert a pending pipeline request into the main device queue. * insert a pending pipeline request into the main device queue.
...@@ -1756,6 +1784,7 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate) ...@@ -1756,6 +1784,7 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate)
unsigned long flags; unsigned long flags;
int error; int error;
int remove_stage = 0; int remove_stage = 0;
idetape_stage_t *active_stage;
#if ONSTREAM_DEBUG #if ONSTREAM_DEBUG
idetape_stage_t *stage; idetape_stage_t *stage;
os_aux_t *aux; os_aux_t *aux;
...@@ -1780,6 +1809,7 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate) ...@@ -1780,6 +1809,7 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate)
/* The request was a pipelined data transfer request */ /* The request was a pipelined data transfer request */
if (tape->active_data_request == rq) { if (tape->active_data_request == rq) {
active_stage = tape->active_stage;
tape->active_stage = NULL; tape->active_stage = NULL;
tape->active_data_request = NULL; tape->active_data_request = NULL;
tape->nr_pending_stages--; tape->nr_pending_stages--;
...@@ -1799,18 +1829,20 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate) ...@@ -1799,18 +1829,20 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate)
if (tape->first_frame_position == OS_DATA_ENDFRAME1) { if (tape->first_frame_position == OS_DATA_ENDFRAME1) {
#if ONSTREAM_DEBUG #if ONSTREAM_DEBUG
if (tape->debug_level >= 2) if (tape->debug_level >= 2)
printk("ide-tape: %s: skipping over config parition..\n", tape->name); printk("ide-tape: %s: skipping over config partition.\n", tape->name);
#endif #endif
tape->onstream_write_error = OS_PART_ERROR; tape->onstream_write_error = OS_PART_ERROR;
if (tape->waiting) if (tape->waiting) {
rq->waiting = NULL;
complete(tape->waiting); complete(tape->waiting);
} }
} }
}
remove_stage = 1; remove_stage = 1;
if (error) { if (error) {
set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
if (error == IDETAPE_ERROR_EOD) if (error == IDETAPE_ERROR_EOD)
idetape_abort_pipeline(drive); idetape_abort_pipeline(drive, active_stage);
if (tape->onstream && !tape->raw && if (tape->onstream && !tape->raw &&
error == IDETAPE_ERROR_GENERAL && error == IDETAPE_ERROR_GENERAL &&
tape->sense.sense_key == 3) { tape->sense.sense_key == 3) {
...@@ -1821,14 +1853,16 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate) ...@@ -1821,14 +1853,16 @@ static int idetape_end_request (ide_drive_t *drive, int uptodate)
tape->nr_pending_stages++; tape->nr_pending_stages++;
tape->next_stage = tape->first_stage; tape->next_stage = tape->first_stage;
rq->current_nr_sectors = rq->nr_sectors; rq->current_nr_sectors = rq->nr_sectors;
if (tape->waiting) if (tape->waiting) {
rq->waiting = NULL;
complete(tape->waiting); complete(tape->waiting);
} }
} }
}
} else if (rq->flags == IDETAPE_READ_RQ) { } else if (rq->flags == IDETAPE_READ_RQ) {
if (error == IDETAPE_ERROR_EOD) { if (error == IDETAPE_ERROR_EOD) {
set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
idetape_abort_pipeline(drive); idetape_abort_pipeline(drive, active_stage);
} }
} }
if (tape->next_stage != NULL && !tape->onstream_write_error) { if (tape->next_stage != NULL && !tape->onstream_write_error) {
...@@ -1879,7 +1913,7 @@ static void idetape_create_request_sense_cmd (idetape_pc_t *pc) ...@@ -1879,7 +1913,7 @@ static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
idetape_init_pc(pc); idetape_init_pc(pc);
pc->c[0] = IDETAPE_REQUEST_SENSE_CMD; pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
pc->c[4] = 20; pc->c[4] = 20;
pc->request_transfer = 18; pc->request_transfer = 20;
pc->callback = &idetape_request_sense_callback; pc->callback = &idetape_request_sense_callback;
} }
...@@ -1980,7 +2014,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) ...@@ -1980,7 +2014,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
status.all = HWIF(drive)->INB(IDE_STATUS_REG); status.all = HWIF(drive)->INB(IDE_STATUS_REG);
if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
if (HWIF(drive)->ide_dma_end(drive)) { if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
/* /*
* A DMA error is sometimes expected. For example, * A DMA error is sometimes expected. For example,
* if the tape is crossing a filemark during a * if the tape is crossing a filemark during a
...@@ -1992,8 +2026,18 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) ...@@ -1992,8 +2026,18 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
* actually transferred (we can't receive that * actually transferred (we can't receive that
* information from the DMA engine on most chipsets). * information from the DMA engine on most chipsets).
*/ */
/*
* On the contrary, a DMA error is never expected;
* it usually indicates a hardware error or abort.
* If the tape crosses a filemark during a READ
* command, it will issue an irq and position itself
* after the filemark (not before). Only a partial
* data transfer will occur, but no DMA error.
* (AS, 19 Apr 2001)
*/
set_bit(PC_DMA_ERROR, &pc->flags); set_bit(PC_DMA_ERROR, &pc->flags);
} else if (!status.b.check) { } else {
pc->actually_transferred = pc->request_transfer; pc->actually_transferred = pc->request_transfer;
idetape_update_buffers(pc); idetape_update_buffers(pc);
} }
...@@ -2029,7 +2073,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) ...@@ -2029,7 +2073,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */
#if IDETAPE_DEBUG_LOG #if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 1) if (tape->debug_level >= 1)
printk(KERN_INFO "ide-tape: %s: I/O error, ", printk(KERN_INFO "ide-tape: %s: I/O error\n",
tape->name); tape->name);
#endif /* IDETAPE_DEBUG_LOG */ #endif /* IDETAPE_DEBUG_LOG */
if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
...@@ -2195,6 +2239,10 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) ...@@ -2195,6 +2239,10 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
BUG(); BUG();
/* Set the interrupt routine */ /* Set the interrupt routine */
ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) /* Begin DMA, if necessary */
(void) (HWIF(drive)->ide_dma_begin(drive));
#endif
/* Send the actual packet */ /* Send the actual packet */
HWIF(drive)->atapi_output_bytes(drive, pc->c, 12); HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
return ide_started; return ide_started;
...@@ -2223,8 +2271,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape ...@@ -2223,8 +2271,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
/* /*
* We will "abort" retrying a packet command in case * We will "abort" retrying a packet command in case
* a legitimate error code was received (crossing a * a legitimate error code was received (crossing a
* filemark, or DMA error in the end of media, for * filemark, or end of the media, for example).
* example).
*/ */
if (!test_bit(PC_ABORT, &pc->flags)) { if (!test_bit(PC_ABORT, &pc->flags)) {
if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
...@@ -2249,7 +2296,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape ...@@ -2249,7 +2296,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
} }
#if IDETAPE_DEBUG_LOG #if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 2) if (tape->debug_level >= 2)
printk(KERN_INFO "ide-tape: Retry number - %d\n", pc->retries); printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]);
#endif /* IDETAPE_DEBUG_LOG */ #endif /* IDETAPE_DEBUG_LOG */
pc->retries++; pc->retries++;
...@@ -2275,10 +2322,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape ...@@ -2275,10 +2322,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
OUT_BYTE(bcount.b.high, IDE_BCOUNTH_REG); OUT_BYTE(bcount.b.high, IDE_BCOUNTH_REG);
OUT_BYTE(bcount.b.low, IDE_BCOUNTL_REG); OUT_BYTE(bcount.b.low, IDE_BCOUNTL_REG);
OUT_BYTE(drive->select.all, IDE_SELECT_REG); OUT_BYTE(drive->select.all, IDE_SELECT_REG);
if (dma_ok) { /* Begin DMA, if necessary */ if (dma_ok) /* Will begin DMA later */
set_bit(PC_DMA_IN_PROGRESS, &pc->flags); set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
(void) (HWIF(drive)->ide_dma_begin(drive));
}
if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
if (HWGROUP(drive)->handler != NULL) /* paranoia check */ if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG(); BUG();
...@@ -3069,7 +3114,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) ...@@ -3069,7 +3114,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
tape->waiting = &wait; tape->waiting = &wait;
spin_unlock(&tape->spinlock); spin_unlock(&tape->spinlock);
wait_for_completion(&wait); wait_for_completion(&wait);
rq->waiting = NULL; /* The stage and its struct request have been deallocated */
tape->waiting = NULL; tape->waiting = NULL;
spin_lock_irq(&tape->spinlock); spin_lock_irq(&tape->spinlock);
} }
...@@ -3333,11 +3378,15 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive) ...@@ -3333,11 +3378,15 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive)
if (tape->chrdev_direction != idetape_direction_read) if (tape->chrdev_direction != idetape_direction_read)
return 0; return 0;
cnt = tape->merge_stage_size / tape->tape_block_size;
if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
++cnt; /* Filemarks count as 1 sector */
tape->merge_stage_size = 0; tape->merge_stage_size = 0;
if (tape->merge_stage != NULL) { if (tape->merge_stage != NULL) {
__idetape_kfree_stage(tape->merge_stage); __idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL; tape->merge_stage = NULL;
} }
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
tape->chrdev_direction = idetape_direction_none; tape->chrdev_direction = idetape_direction_none;
if (tape->first_stage == NULL) if (tape->first_stage == NULL)
...@@ -3349,9 +3398,14 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive) ...@@ -3349,9 +3398,14 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive)
idetape_wait_for_request(drive, tape->active_data_request); idetape_wait_for_request(drive, tape->active_data_request);
spin_unlock_irqrestore(&tape->spinlock, flags); spin_unlock_irqrestore(&tape->spinlock, flags);
cnt = tape->nr_stages - tape->nr_pending_stages; while (tape->first_stage != NULL) {
while (tape->first_stage != NULL) struct request *rq_ptr = &tape->first_stage->rq;
cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
++cnt;
idetape_remove_stage_head(drive); idetape_remove_stage_head(drive);
}
tape->nr_pending_stages = 0; tape->nr_pending_stages = 0;
tape->max_stages = tape->min_pipeline; tape->max_stages = tape->min_pipeline;
return cnt; return cnt;
...@@ -3946,7 +4000,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages) ...@@ -3946,7 +4000,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
*/ */
bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio); bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
if (bytes_read < 0) { if (bytes_read < 0) {
kfree(tape->merge_stage); __idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL; tape->merge_stage = NULL;
tape->chrdev_direction = idetape_direction_none; tape->chrdev_direction = idetape_direction_none;
return bytes_read; return bytes_read;
...@@ -3959,7 +4013,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages) ...@@ -3959,7 +4013,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
rq.sector = tape->first_frame_position; rq.sector = tape->first_frame_position;
rq.nr_sectors = rq.current_nr_sectors = blocks; rq.nr_sectors = rq.current_nr_sectors = blocks;
if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
tape->nr_stages <= max_stages) { tape->nr_stages < max_stages) {
new_stage = idetape_kmalloc_stage(tape); new_stage = idetape_kmalloc_stage(tape);
while (new_stage != NULL) { while (new_stage != NULL) {
new_stage->rq = rq; new_stage->rq = rq;
...@@ -4068,6 +4122,12 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) ...@@ -4068,6 +4122,12 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks); printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
#endif /* IDETAPE_DEBUG_LOG */ #endif /* IDETAPE_DEBUG_LOG */
/*
* If we are at a filemark, return a read length of 0
*/
if (test_bit(IDETAPE_FILEMARK, &tape->flags))
return 0;
/* /*
* Wait for the next logical block to be available at the head * Wait for the next logical block to be available at the head
* of the pipeline * of the pipeline
...@@ -4097,14 +4157,7 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) ...@@ -4097,14 +4157,7 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
} }
if (rq_ptr->errors == IDETAPE_ERROR_EOD) if (rq_ptr->errors == IDETAPE_ERROR_EOD)
return 0; return 0;
if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) { else {
idetape_switch_buffers(tape, tape->first_stage);
set_bit(IDETAPE_FILEMARK, &tape->flags);
#if USE_IOTRACE
IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
#endif
calculate_speeds(drive);
} else {
idetape_switch_buffers(tape, tape->first_stage); idetape_switch_buffers(tape, tape->first_stage);
if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) { if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
#if ONSTREAM_DEBUG #if ONSTREAM_DEBUG
...@@ -4112,7 +4165,8 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) ...@@ -4112,7 +4165,8 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read); printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
#endif #endif
} }
clear_bit(IDETAPE_FILEMARK, &tape->flags); if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
set_bit(IDETAPE_FILEMARK, &tape->flags);
spin_lock_irqsave(&tape->spinlock, flags); spin_lock_irqsave(&tape->spinlock, flags);
idetape_remove_stage_head(drive); idetape_remove_stage_head(drive);
spin_unlock_irqrestore(&tape->spinlock, flags); spin_unlock_irqrestore(&tape->spinlock, flags);
...@@ -4456,34 +4510,50 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c ...@@ -4456,34 +4510,50 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
return retval; return retval;
} }
if (mt_count == 0)
return 0;
if (MTBSF == mt_op || MTBSFM == mt_op) {
if (!tape->capabilities.sprev)
return -EIO;
mt_count = - mt_count;
}
if (tape->chrdev_direction == idetape_direction_read) { if (tape->chrdev_direction == idetape_direction_read) {
/* /*
* We have a read-ahead buffer. Scan it for crossed * We have a read-ahead buffer. Scan it for crossed
* filemarks. * filemarks.
*/ */
tape->merge_stage_size = 0; tape->merge_stage_size = 0;
clear_bit(IDETAPE_FILEMARK, &tape->flags); if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
++count;
while (tape->first_stage != NULL) { while (tape->first_stage != NULL) {
idetape_wait_first_stage(drive);
if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
count++;
if (count == mt_count) { if (count == mt_count) {
switch (mt_op) { if (mt_op == MTFSFM)
case MTFSF: set_bit(IDETAPE_FILEMARK, &tape->flags);
spin_lock_irqsave(&tape->spinlock, flags); return 0;
idetape_remove_stage_head(drive);
spin_unlock_irqrestore(&tape->spinlock, flags);
case MTFSFM:
return (0);
default:
break;
}
} }
spin_lock_irqsave(&tape->spinlock, flags); spin_lock_irqsave(&tape->spinlock, flags);
idetape_remove_stage_head(drive); if (tape->first_stage == tape->active_stage) {
/*
* We have reached the active stage in the read pipeline.
* There is no point in allowing the drive to continue
* reading any farther, so we stop the pipeline.
*
* This section should be moved to a separate subroutine,
* because a similar function is performed in
* __idetape_discard_read_pipeline(), for example.
*/
tape->next_stage = NULL;
spin_unlock_irqrestore(&tape->spinlock, flags); spin_unlock_irqrestore(&tape->spinlock, flags);
idetape_wait_first_stage(drive);
tape->next_stage = tape->first_stage->next;
} else
spin_unlock_irqrestore(&tape->spinlock, flags);
if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
++count;
idetape_remove_stage_head(drive);
} }
idetape_discard_read_pipeline(drive, 1); idetape_discard_read_pipeline(drive, 0);
} }
/* /*
...@@ -4492,25 +4562,17 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c ...@@ -4492,25 +4562,17 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
*/ */
switch (mt_op) { switch (mt_op) {
case MTFSF: case MTFSF:
case MTBSF:
idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK); idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
return (idetape_queue_pc_tail(drive, &pc)); return (idetape_queue_pc_tail(drive, &pc));
case MTFSFM: case MTFSFM:
if (!tape->capabilities.sprev)
return (-EIO);
retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
if (retval) return (retval);
return (idetape_space_over_filemarks(drive, MTBSF, 1));
case MTBSF:
if (!tape->capabilities.sprev)
return (-EIO);
idetape_create_space_cmd(&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
return (idetape_queue_pc_tail(drive, &pc));
case MTBSFM: case MTBSFM:
if (!tape->capabilities.sprev) if (!tape->capabilities.sprev)
return (-EIO); return (-EIO);
retval = idetape_space_over_filemarks(drive, MTBSF, mt_count+count); retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
if (retval) return (retval); if (retval) return (retval);
return (idetape_space_over_filemarks(drive, MTFSF, 1)); count = (MTBSFM == mt_op ? 1 : -1);
return (idetape_space_over_filemarks(drive, MTFSF, count));
default: default:
printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op); printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
return (-EIO); return (-EIO);
...@@ -4861,7 +4923,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf, ...@@ -4861,7 +4923,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
*/ */
retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio); retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
if (retval < 0) { if (retval < 0) {
kfree(tape->merge_stage); __idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL; tape->merge_stage = NULL;
tape->chrdev_direction = idetape_direction_none; tape->chrdev_direction = idetape_direction_none;
return retval; return retval;
...@@ -5447,7 +5509,9 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) ...@@ -5447,7 +5509,9 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
return -EBUSY; return -EBUSY;
} }
if (tape->onstream)
idetape_read_position(drive); idetape_read_position(drive);
if (tape->chrdev_direction != idetape_direction_read)
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
if (tape->chrdev_direction == idetape_direction_none) { if (tape->chrdev_direction == idetape_direction_none) {
...@@ -5520,12 +5584,13 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) ...@@ -5520,12 +5584,13 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
if (minor < 128) if (minor < 128)
(void) idetape_rewind_tape(drive); (void) idetape_rewind_tape(drive);
if (tape->chrdev_direction == idetape_direction_none) { if (tape->chrdev_direction == idetape_direction_none) {
if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) { if (tape->door_locked == DOOR_LOCKED) {
if (idetape_create_prevent_cmd(drive, &pc, 0)) if (idetape_create_prevent_cmd(drive, &pc, 0)) {
if (!idetape_queue_pc_tail(drive, &pc)) if (!idetape_queue_pc_tail(drive, &pc))
tape->door_locked = DOOR_UNLOCKED; tape->door_locked = DOOR_UNLOCKED;
} }
} }
}
clear_bit(IDETAPE_BUSY, &tape->flags); clear_bit(IDETAPE_BUSY, &tape->flags);
unlock_kernel(); unlock_kernel();
return 0; return 0;
...@@ -5556,34 +5621,34 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) ...@@ -5556,34 +5621,34 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n"); printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
printk(KERN_INFO "ide-tape: Protocol Type: "); printk(KERN_INFO "ide-tape: Protocol Type: ");
switch (gcw.protocol) { switch (gcw.protocol) {
case 0: case 1: printk(KERN_INFO "ATA\n");break; case 0: case 1: printk("ATA\n");break;
case 2: printk(KERN_INFO "ATAPI\n");break; case 2: printk("ATAPI\n");break;
case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break; case 3: printk("Reserved (Unknown to ide-tape)\n");break;
} }
printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type); printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);
switch (gcw.device_type) { switch (gcw.device_type) {
case 0: printk(KERN_INFO "Direct-access Device\n");break; case 0: printk("Direct-access Device\n");break;
case 1: printk(KERN_INFO "Streaming Tape Device\n");break; case 1: printk("Streaming Tape Device\n");break;
case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break; case 2: case 3: case 4: printk("Reserved\n");break;
case 5: printk(KERN_INFO "CD-ROM Device\n");break; case 5: printk("CD-ROM Device\n");break;
case 6: printk(KERN_INFO "Reserved\n"); case 6: printk("Reserved\n");
case 7: printk(KERN_INFO "Optical memory Device\n");break; case 7: printk("Optical memory Device\n");break;
case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break; case 0x1f: printk("Unknown or no Device type\n");break;
default: printk(KERN_INFO "Reserved\n"); default: printk("Reserved\n");
} }
printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n"); printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");
printk(KERN_INFO "ide-tape: Command Packet DRQ Type: "); printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
switch (gcw.drq_type) { switch (gcw.drq_type) {
case 0: printk(KERN_INFO "Microprocessor DRQ\n");break; case 0: printk("Microprocessor DRQ\n");break;
case 1: printk(KERN_INFO "Interrupt DRQ\n");break; case 1: printk("Interrupt DRQ\n");break;
case 2: printk(KERN_INFO "Accelerated DRQ\n");break; case 2: printk("Accelerated DRQ\n");break;
case 3: printk(KERN_INFO "Reserved\n");break; case 3: printk("Reserved\n");break;
} }
printk(KERN_INFO "ide-tape: Command Packet Size: "); printk(KERN_INFO "ide-tape: Command Packet Size: ");
switch (gcw.packet_size) { switch (gcw.packet_size) {
case 0: printk(KERN_INFO "12 bytes\n");break; case 0: printk("12 bytes\n");break;
case 1: printk(KERN_INFO "16 bytes\n");break; case 1: printk("16 bytes\n");break;
default: printk(KERN_INFO "Reserved\n");break; default: printk("Reserved\n");break;
} }
printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model); printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev); printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
...@@ -5599,45 +5664,45 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) ...@@ -5599,45 +5664,45 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
printk(KERN_INFO "ide-tape: Single Word DMA supported modes: "); printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
for (i=0,mask=1;i<8;i++,mask=mask << 1) { for (i=0,mask=1;i<8;i++,mask=mask << 1) {
if (id->dma_1word & mask) if (id->dma_1word & mask)
printk(KERN_INFO "%d ",i); printk("%d ",i);
if (id->dma_1word & (mask << 8)) if (id->dma_1word & (mask << 8))
printk(KERN_INFO "(active) "); printk("(active) ");
} }
printk(KERN_INFO "\n"); printk("\n");
printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: "); printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
for (i=0,mask=1;i<8;i++,mask=mask << 1) { for (i=0,mask=1;i<8;i++,mask=mask << 1) {
if (id->dma_mword & mask) if (id->dma_mword & mask)
printk(KERN_INFO "%d ",i); printk("%d ",i);
if (id->dma_mword & (mask << 8)) if (id->dma_mword & (mask << 8))
printk(KERN_INFO "(active) "); printk("(active) ");
} }
printk(KERN_INFO "\n"); printk("\n");
if (id->field_valid & 0x0002) { if (id->field_valid & 0x0002) {
printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n", printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
id->eide_pio_modes & 1 ? "Mode 3":"None"); id->eide_pio_modes & 1 ? "Mode 3":"None");
printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: "); printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
if (id->eide_dma_min == 0) if (id->eide_dma_min == 0)
printk(KERN_INFO "Not supported\n"); printk("Not supported\n");
else else
printk(KERN_INFO "%d ns\n",id->eide_dma_min); printk("%d ns\n",id->eide_dma_min);
printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: "); printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
if (id->eide_dma_time == 0) if (id->eide_dma_time == 0)
printk(KERN_INFO "Not supported\n"); printk("Not supported\n");
else else
printk(KERN_INFO "%d ns\n",id->eide_dma_time); printk("%d ns\n",id->eide_dma_time);
printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: "); printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
if (id->eide_pio == 0) if (id->eide_pio == 0)
printk(KERN_INFO "Not supported\n"); printk("Not supported\n");
else else
printk(KERN_INFO "%d ns\n",id->eide_pio); printk("%d ns\n",id->eide_pio);
printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: "); printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
if (id->eide_pio_iordy == 0) if (id->eide_pio_iordy == 0)
printk(KERN_INFO "Not supported\n"); printk("Not supported\n");
else else
printk(KERN_INFO "%d ns\n",id->eide_pio_iordy); printk("%d ns\n",id->eide_pio_iordy);
} else } else
printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
...@@ -5946,9 +6011,9 @@ static void idetape_add_settings (ide_drive_t *drive) ...@@ -5946,9 +6011,9 @@ static void idetape_add_settings (ide_drive_t *drive)
* drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
*/ */
ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL); ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL);
ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL);
ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL); ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL);
ide_add_setting(drive, "pipeline_pending",SETTING_READ,-1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL); ide_add_setting(drive, "pipeline_pending",SETTING_READ,-1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL);
ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL); ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL);
...@@ -6063,8 +6128,11 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) ...@@ -6063,8 +6128,11 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
si_meminfo(&si); si_meminfo(&si);
if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10) if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size); tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
tape->min_pipeline = tape->max_stages; tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
tape->max_pipeline = tape->max_stages * 2; tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
if (tape->max_stages == 0)
tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
t1 = (tape->stage_size * HZ) / (speed * 1000); t1 = (tape->stage_size * HZ) / (speed * 1000);
tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125); tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment