linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* PATCH for ide-tape driver
@ 2003-03-07 23:00 Frans Pop
  2003-03-08 20:01 ` Alan Stern
  0 siblings, 1 reply; 6+ messages in thread
From: Frans Pop @ 2003-03-07 23:00 UTC (permalink / raw)
  To: linux-kernel; +Cc: gadio, zaitcev, stern

I have been experiencing problems with this driver.
When I do 'tar cf /dev/tape --verify <filespec>', I consistently get an error 
message 'Unexpected EOF in archive'.
I have Googled for this problem and found others have it to, but no sulution 
available.

I also tried the scsi-ide driver, but this produced errors as well, so I 
decided to try to debug the ide-tape driver.

My system is a Compaq Deskpro Pentium 300 with Debian Woody 3.0r1 that I 
upgraded to latest stable kernel 2.4.21-pre4 to work on this patch.
My tape drive is a Conner CCT-8000A (TR-4).
I have tested and created the patch working from v1.17c of ide-tape.c.

I have created a patch after fairly extensive debugging and testing.
During this process I found 2 technical bugs in the driver that I fixed also. 
These bugs produced the following log messages:
- bug: nr_stages should be 0 now
- ide-tape pipeline bug: first_stage 00000000, next_stage 00000000, 
last_stage 00000000, nr_stages 1

I have created a website at http://home.tiscali.nl/isildur/ where the patch 
can be downloaded. On this site I have documented quite extensively what I 
have done.

IMO there seem to be some important discrepancies in the way file spacing is 
handled in the kernel and the way it is used in tar and mt. This is also 
documented on the website.

I am currently looking for feedback and people to test my patch.

TIA,

Frans Pop

P.S. Please reply with CC to private mail as I am not on the list.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH for ide-tape driver
  2003-03-07 23:00 PATCH for ide-tape driver Frans Pop
@ 2003-03-08 20:01 ` Alan Stern
  0 siblings, 0 replies; 6+ messages in thread
From: Alan Stern @ 2003-03-08 20:01 UTC (permalink / raw)
  To: Frans Pop; +Cc: linux-kernel, gadio, zaitcev

On Sat, 8 Mar 2003, Frans Pop wrote:

> I have been experiencing problems with this driver.
> When I do 'tar cf /dev/tape --verify <filespec>', I consistently get an error 
> message 'Unexpected EOF in archive'.
> I have Googled for this problem and found others have it to, but no sulution 
> available.
> 
> I also tried the scsi-ide driver, but this produced errors as well, so I 
> decided to try to debug the ide-tape driver.
> 
> My system is a Compaq Deskpro Pentium 300 with Debian Woody 3.0r1 that I 
> upgraded to latest stable kernel 2.4.21-pre4 to work on this patch.
> My tape drive is a Conner CCT-8000A (TR-4).
> I have tested and created the patch working from v1.17c of ide-tape.c.
> 
> I have created a patch after fairly extensive debugging and testing.
> During this process I found 2 technical bugs in the driver that I fixed also. 
> These bugs produced the following log messages:
> - bug: nr_stages should be 0 now
> - ide-tape pipeline bug: first_stage 00000000, next_stage 00000000, 
> last_stage 00000000, nr_stages 1
> 
> I have created a website at http://home.tiscali.nl/isildur/ where the patch 
> can be downloaded. On this site I have documented quite extensively what I 
> have done.

Frans:

Your web site is very impressive.  Clearly you have spent a lot of time 
and effort to analyze the problems and solve them.

When I was working on the ide-tape driver, I found it rather confusing and
oddly-structured -- the result of many accumulated additions and changes,
no doubt.  I salute anyone who is willing to go to the trouble of figuring 
out how it really operates.  If you feel up to a more prolonged project, 
here are some ideas for things you could do:

	Take out all the Onstream additions.  There really needs to be
	two versions of the driver: one for Onstream tape drives and one 
	for everything else.  That will simplify the code immensely.

	Add an option to remove the write pipeline, thereby making output
	synchronous.  While this will slow the operation, it will make it
	possible for the driver to accurately report write errors, which
	is pretty important when performing backups.

	Make the pipeline options configurable at module load time as
	module parameters, as opposed to the awkward procfs interface
	currently there.  Better yet, implement the new driver model
	in Linux 2.5.

	Clean up the pipline operations and make them more obviously
	correct.  In particular, I am far from convinced that the
	feedback mechanism for adding/removing pipeline stages is 
	adequate.

	Clean up the error logging code: replace preprocessor commands
	with inline functions.

Regarding your changes:  I won't have a chance to go over the functional
parts of your patch until next week.  Your point that an ioctl following a
write should automatically create a filemark is correct.  The fact that it
did not do so before is a reflection on the ad-hoc structuring of the
driver.

Your additional error logging looks fine at first glance.


> IMO there seem to be some important discrepancies in the way file spacing is 
> handled in the kernel and the way it is used in tar and mt. This is also 
> documented on the website.

I read your web pages.  I can't speak about tar (my tape backups generally 
use 'backup' and 'restore') and I don't know what it does when you specify 
--verify.  (You might try reading the source code for tar to find out what 
the mystery ioctl is intended for.)

I'm not sure what version of mt you are using.  Here's an extract from the 
man page on my system (RedHat 7.1, version 0.5b of the mt-st package, 
man page copyrighted 1998):

       fsf    Forward space count files.  The tape is  positioned
              on the first block of the next file.

       fsfm   Forward  space count files.  The tape is positioned
              on the last block of the previous file.

       bsf    Backward space count files.  The tape is positioned
              on the last block of the previous file.

       bsfm   Backward space count files.  The tape is positioned
              on the first block of the next file.

This agrees with mtio.h and the behavior you observed (no surprise there; 
my patch addressed that very issue).

On older Unix-type systems, such as Irix or AIX, the fsfm and bsfm 
commands didn't exist.  On those systems, bsf was specified as leaving the 
tape on the beginning-of-tape side of the last filemark crossed.

Furthermore, these commands are implemented by issuing the SPACE command 
to the drive.  This command is documented in the SCSI specification as 
leaving the tape on the B.O.T. side for backwards seeks.  That's what you 
would expect, since in its most straightforward mode of operation the 
firmware won't know that the tape has reached a filemark until it has 
gone past the filemark.

All this makes it sound like the user interface for your version of mt is 
the odd man out.  Of course, the fact that the user interface is different 
doesn't _necessarily_ imply an inconsistency.  In principle it is possible 
that your mt implements the bsf command by issuing the equivalent of a 
bsfm ioctl call.  In practice, however, I doubt that is the case.


I will write back after I've had the time to go over your patch.  Thanks a 
lot for all your work on the driver.

Alan Stern


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Patch for ide-tape driver
  2002-12-10  0:37 ` Alan Cox
  2002-12-10 21:15   ` Alan Stern
@ 2002-12-30 16:34   ` Alan Stern
  1 sibling, 0 replies; 6+ messages in thread
From: Alan Stern @ 2002-12-30 16:34 UTC (permalink / raw)
  To: Alan Cox; +Cc: Linux Kernel Mailing List

[-- Attachment #1: Type: TEXT/PLAIN, Size: 284 bytes --]

Alan:

Here is another copy of my multiple-bug-fix patch for the ide-tape driver,
as of 2.5.53.  The corresponding patch for 2.4.21 has already been
accepted by Marcelo.  Please apply this to the current kernel (or send it
on up the line) when you have a chance.

Thanks.

Alan Stern

[-- Attachment #2: Patch for ide-tape driver, 2.5.53 --]
[-- Type: TEXT/PLAIN, Size: 24754 bytes --]

--- linux/drivers/ide/ide-tape.c.orig	Mon Dec  9 14:42:07 2002
+++ linux/drivers/ide/ide-tape.c	Tue Dec 10 15:40:19 2002
@@ -1,5 +1,5 @@
 /*
- * 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>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- 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
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		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/module.h>
@@ -577,9 +599,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	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_INCREASE_STAGES_RATE	 20
 
@@ -601,8 +624,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -1610,24 +1633,6 @@
 	}
 }
 
-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".
  */
@@ -1672,7 +1677,7 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
 #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 = min(tape->max_stages, tape->max_pipeline);
 }
@@ -1745,6 +1750,29 @@
 	}
 }
 
+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
  *	insert a pending pipeline request into the main device queue.
@@ -1756,6 +1784,7 @@
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1780,6 +1809,7 @@
 
 	/* The request was a pipelined data transfer request */
 	if (tape->active_data_request == rq) {
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1799,18 +1829,20 @@
 				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					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
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
 				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline(drive);
+					idetape_abort_pipeline(drive, active_stage);
 				if (tape->onstream && !tape->raw &&
 				    error == IDETAPE_ERROR_GENERAL &&
 				    tape->sense.sense_key == 3) {
@@ -1821,14 +1853,16 @@
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->flags == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				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) {
@@ -1879,7 +1913,7 @@
 	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -1980,7 +2014,7 @@
 	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	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,
 			 * if the tape is crossing a filemark during a
@@ -1992,8 +2026,18 @@
 			 * actually transferred (we can't receive that
 			 * 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);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers(pc);
 		}
@@ -2029,7 +2073,7 @@
 		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			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);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2195,6 +2239,10 @@
 		BUG();
 	/* Set the interrupt routine */
 	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 */
 	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
@@ -2223,8 +2271,7 @@
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit(PC_ABORT, &pc->flags)) {
 			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
@@ -2249,7 +2296,7 @@
 	}
 #if IDETAPE_DEBUG_LOG
 	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 */
 
 	pc->retries++;
@@ -2275,10 +2322,8 @@
 	OUT_BYTE(bcount.b.high,     IDE_BCOUNTH_REG);
 	OUT_BYTE(bcount.b.low,      IDE_BCOUNTL_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);
-		(void) (HWIF(drive)->ide_dma_begin(drive));
-	}
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
 		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
 			BUG();
@@ -3069,7 +3114,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3333,11 +3378,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		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;
 	if (tape->merge_stage != NULL) {
 		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3349,9 +3398,14 @@
 		idetape_wait_for_request(drive, tape->active_data_request);
 	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);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3946,7 +4000,7 @@
 		 */
 		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
 		if (bytes_read < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3959,7 +4013,7 @@
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
-	    tape->nr_stages <= max_stages) {
+	    tape->nr_stages < max_stages) {
 		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
@@ -4069,6 +4123,12 @@
 #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
 	 * of the pipeline
 	 */
@@ -4097,14 +4157,7 @@
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		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 {
+	else {
 		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
@@ -4112,7 +4165,8 @@
 				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
 #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);
 		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4455,6 +4509,14 @@
 		tape->restart_speed_control_req = 1;
 		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) {
 		/*
@@ -4462,28 +4524,36 @@
 		 *	filemarks.
 		 */
 		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) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head(drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
+			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);
+				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);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline(drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4492,25 +4562,17 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
+		case MTBSF:
 			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
 			return (idetape_queue_pc_tail(drive, &pc));
 		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:
 			if (!tape->capabilities.sprev)
 				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);
-			return (idetape_space_over_filemarks(drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
 			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
@@ -4861,7 +4923,7 @@
 		 */
 		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
 		if (retval < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -5447,8 +5509,10 @@
 		printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
-	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->onstream)
+		idetape_read_position(drive);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
@@ -5520,10 +5584,11 @@
 	if (minor < 128)
 		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
 				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 	}
 	clear_bit(IDETAPE_BUSY, &tape->flags);
@@ -5556,34 +5621,34 @@
 	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
 	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk(KERN_INFO "ATA\n");break;
-		case 2:	printk(KERN_INFO "ATAPI\n");break;
-		case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk(KERN_INFO "Direct-access Device\n");break;
-		case 1: printk(KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break;
-		case 5: printk(KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk(KERN_INFO "Reserved\n");
-		case 7: printk(KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break;
-		default: printk(KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
 	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
 	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk(KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk(KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk(KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk(KERN_INFO "12 bytes\n");break;
-		case 1: printk(KERN_INFO "16 bytes\n");break;
-		default: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
 	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
@@ -5599,45 +5664,45 @@
 	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		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: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk(KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk(KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
 		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
 			id->eide_pio_modes & 1 ? "Mode 3":"None");
 		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_dma_time == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_pio == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_pio_iordy == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
 		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
@@ -5946,9 +6011,9 @@
  *			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,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			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_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_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,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			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_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);
@@ -6063,8 +6128,11 @@
 	si_meminfo(&si);
 	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->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	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);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Patch for ide-tape driver
  2002-12-10  0:37 ` Alan Cox
@ 2002-12-10 21:15   ` Alan Stern
  2002-12-30 16:34   ` Alan Stern
  1 sibling, 0 replies; 6+ messages in thread
From: Alan Stern @ 2002-12-10 21:15 UTC (permalink / raw)
  To: Alan Cox, Marcelo Tosatti; +Cc: Linux Kernel Mailing List

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1128 bytes --]

On 10 Dec 2002, Alan Cox wrote:

> On Mon, 2002-12-09 at 20:03, Alan Stern wrote:
> > Attached are patch files for both 2.4.20 and 2.5.50.  Please apply them
> > when you have a chance.
>
> 2.4.21pre1 has updated IDE core code so it probably wants a bit of a
> resync before it can go in. The 2.5.50 one is matching the 2.4.21pre1
> IDE core so it shouldnt be too bad.

All right.  I cloned Marcelo's 2.4 tree from bkbits.net this morning, and
sure enough, there are numerous changes with respect to the distribution
version of 2.4.20.  I have updated my patch for the ide-tape driver
accordingly and attached it.  Please don't tell me that yet more changes
have been made in the meantime -- it's very difficult to hit a moving
target! :-)

So far as I am aware, there have not been any changes to the 2.5.50
version of the driver, so the patch file I submitted earlier should still
apply.

Alan Stern


P.S.: It is a considerable nuisance having to clone an entire kernel tree
just to get the current version of one file.  Can anyone tell me if there
is a quicker, less bandwidth-intensive way of accomplishing the same
thing?

[-- Attachment #2: Patch for 2.4.21 version of ide-tape.c --]
[-- Type: TEXT/PLAIN, Size: 24604 bytes --]

--- linux/drivers/ide/ide-tape.c.orig	Tue Dec 10 11:15:30 2002
+++ linux/drivers/ide/ide-tape.c	Tue Dec 10 15:37:51 2002
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
+ * linux/drivers/ide/ide-tape.c		Version 1.17b	Dec, 2002
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- Limit size of pipeline
+ * Ver 1.17b Dec 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
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		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/module.h>
@@ -576,9 +598,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	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_INCREASE_STAGES_RATE	 20
 
@@ -600,8 +623,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -1699,25 +1722,6 @@
 	}
 }
 
-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: %s called\n",
-			tape->name, __FUNCTION__);
-#endif
-	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
-		stage = stage->next;
-	}
-}
-
 /*
  *	idetape_active_next_stage will declare the next stage as "active".
  */
@@ -1763,7 +1767,7 @@
 		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	tape->max_stages += increase;
+	tape->max_stages += IDE_MAX(increase, 1);
 	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
 	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
 }
@@ -1839,6 +1843,30 @@
 	}
 }
 
+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: %s called\n",
+			tape->name, __FUNCTION__);
+#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
  *	insert a pending pipeline request into the main device queue.
@@ -1850,6 +1878,7 @@
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1873,6 +1902,7 @@
 	spin_lock_irqsave(&tape->spinlock, flags);
 	if (tape->active_data_request == rq) {
 		/* The request was a pipelined data transfer request */
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1892,18 +1922,20 @@
 				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					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
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
 				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline(drive);
+					idetape_abort_pipeline(drive, active_stage);
 				if (tape->onstream && !tape->raw &&
 				    error == IDETAPE_ERROR_GENERAL &&
 				    tape->sense.sense_key == 3) {
@@ -1914,14 +1946,16 @@
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				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) {
@@ -1969,7 +2003,7 @@
 	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -2071,7 +2105,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	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,
 			 * if the tape is crossing a filemark during a
@@ -2083,8 +2117,18 @@
 			 * actually transferred (we can't receive that
 			 * 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);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
@@ -2123,7 +2167,7 @@
 			/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			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);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2314,6 +2358,11 @@
 		BUG();
 	/* Set the interrupt routine */
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	/* Begin DMA, if necessary */
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+#endif
 	/* Send the actual packet */
 	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
@@ -2343,8 +2392,7 @@
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
 			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
@@ -2371,7 +2419,8 @@
 	}
 #if IDETAPE_DEBUG_LOG
 	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 */
 
 	pc->retries++;
@@ -2404,10 +2453,8 @@
 	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
 	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (feature.b.dma) {		/* Begin DMA, if necessary */
+	if (feature.b.dma)		/* Will begin DMA later */
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->ide_dma_begin(drive));
-	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
 		if (HWGROUP(drive)->handler != NULL)
@@ -3238,7 +3285,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3510,11 +3557,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		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;
 	if (tape->merge_stage != NULL) {
 		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3526,9 +3577,14 @@
 		idetape_wait_for_request(drive, tape->active_data_request);
 	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);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -4151,7 +4207,7 @@
 		 */
 		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
 		if (bytes_read < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -4164,7 +4220,7 @@
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
-	    tape->nr_stages <= max_stages) {
+	    tape->nr_stages < max_stages) {
 		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
@@ -4287,6 +4343,12 @@
 #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
 	 * of the pipeline
 	 */
@@ -4315,14 +4377,7 @@
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		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 {
+	else {
 		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
@@ -4331,7 +4386,8 @@
 					"bytes_read %d\n", bytes_read);
 #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);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4714,6 +4770,14 @@
 		tape->restart_speed_control_req = 1;
 		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) {
 		/*
@@ -4721,28 +4785,36 @@
 		 *	filemarks.
 		 */
 		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) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head(drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
+			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);
+				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);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline(drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4751,25 +4823,17 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
+		case MTBSF:
 			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
 			return (idetape_queue_pc_tail(drive, &pc));
 		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:
 			if (!tape->capabilities.sprev)
 				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);
-			return (idetape_space_over_filemarks(drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
 			printk(KERN_ERR "ide-tape: MTIO operation %d not "
 				"supported\n", mt_op);
@@ -5117,7 +5181,7 @@
 		 */
 		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
 		if (retval < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -5701,9 +5765,11 @@
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
+	if (tape->onstream)
+		idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
@@ -5776,10 +5842,11 @@
 	if (minor < 128)
 		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
 				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 		MOD_DEC_USE_COUNT;
 	}
@@ -5813,34 +5880,34 @@
 	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
 	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk(KERN_INFO "ATA\n");break;
-		case 2:	printk(KERN_INFO "ATAPI\n");break;
-		case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk(KERN_INFO "Direct-access Device\n");break;
-		case 1: printk(KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break;
-		case 5: printk(KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk(KERN_INFO "Reserved\n");
-		case 7: printk(KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break;
-		default: printk(KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
 	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
 	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk(KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk(KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk(KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk(KERN_INFO "12 bytes\n");break;
-		case 1: printk(KERN_INFO "16 bytes\n");break;
-		default: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
 	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
@@ -5856,44 +5923,44 @@
 	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		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: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk(KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk(KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
 		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
 		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_dma_time == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_pio == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_pio_iordy == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
 		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
@@ -6205,9 +6272,9 @@
  *			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,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			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_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_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,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			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_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);
@@ -6317,8 +6384,11 @@
 	si_meminfo(&si);
 	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->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = IDE_MIN(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	tape->min_pipeline = IDE_MIN(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+	tape->max_pipeline = IDE_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);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Patch for ide-tape driver
  2002-12-09 20:03 Patch " Alan Stern
@ 2002-12-10  0:37 ` Alan Cox
  2002-12-10 21:15   ` Alan Stern
  2002-12-30 16:34   ` Alan Stern
  0 siblings, 2 replies; 6+ messages in thread
From: Alan Cox @ 2002-12-10  0:37 UTC (permalink / raw)
  To: Alan Stern; +Cc: Marcelo Tosatti, Linux Kernel Mailing List

On Mon, 2002-12-09 at 20:03, Alan Stern wrote:
> Attached are patch files for both 2.4.20 and 2.5.50.  Please apply them
> when you have a chance.

2.4.21pre1 has updated IDE core code so it probably wants a bit of a
resync before it can go in. The 2.5.50 one is matching the 2.4.21pre1
IDE core so it shouldnt be too bad.

The one current difference is that 2.5.50 has ->vdma on devices which if
set indicates you should set up as if for DMA but issue PIO commands.
Its used for controllers that support DMA for PIO mode transfers


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Patch for ide-tape driver
@ 2002-12-09 20:03 Alan Stern
  2002-12-10  0:37 ` Alan Cox
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Stern @ 2002-12-09 20:03 UTC (permalink / raw)
  To: Alan Cox, Marcelo Tosatti; +Cc: Linux kernel mailing list

[-- Attachment #1: Type: TEXT/PLAIN, Size: 429 bytes --]

Alan, Marcelo, and all:

As suggested earlier by Alan Cox, now that 2.4.20 has been released I am
resubmitting my patches for the ide-tape driver.  It fixes a few nasty
bugs and makes some other small improvements in the original.  It has been
tested by Willem Riede, who maintains the OnStream tape driver.

Attached are patch files for both 2.4.20 and 2.5.50.  Please apply them
when you have a chance.

Thank you,

Alan Stern

[-- Attachment #2: ide-tape patch for 2.4.20 --]
[-- Type: TEXT/PLAIN, Size: 24981 bytes --]

--- linux/drivers/ide/ide-tape.c.orig	Wed Oct 16 11:47:36 2002
+++ linux/drivers/ide/ide-tape.c	Thu Oct 17 15:12:28 2002
@@ -1,5 +1,5 @@
 /*
- * 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>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- 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
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		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/module.h>
@@ -577,9 +599,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	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_INCREASE_STAGES_RATE	 20
 
@@ -601,8 +624,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -1696,24 +1719,6 @@
 	}
 }
 
-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.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
-		stage = stage->next;
-	}
-}
-
 /*
  *	idetape_active_next_stage will declare the next stage as "active".
  */
@@ -1758,7 +1763,7 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	tape->max_stages += increase;
+	tape->max_stages += IDE_MAX(increase, 1);
 	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
 	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
 }
@@ -1831,6 +1836,29 @@
 	}
 }
 
+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
  *	insert a pending pipeline request into the main device queue.
@@ -1843,6 +1871,7 @@
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1865,6 +1894,7 @@
 
 	spin_lock_irqsave(&tape->spinlock, flags);
 	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1887,15 +1917,17 @@
 						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
 				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline (drive);
+					idetape_abort_pipeline(drive, active_stage);
 				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
 					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
@@ -1904,14 +1936,16 @@
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				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) {
@@ -1957,7 +1991,7 @@
 	idetape_init_pc (pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -2057,7 +2091,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+		if (HWIF(drive)->dmaproc(ide_dma_end, drive) || status.b.check) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2069,8 +2103,18 @@
 			 * actually transferred (we can't receive that
 			 * 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);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
@@ -2103,7 +2147,7 @@
 		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
+				printk(KERN_INFO "ide-tape: %s: I/O error\n",tape->name);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
@@ -2255,6 +2299,10 @@
 	}
 	tape->cmd_start_time = jiffies;
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))		/* Begin DMA, if necessary */
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+#endif
 	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
 	return ide_started;
 }
@@ -2279,8 +2327,7 @@
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
 			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
@@ -2297,7 +2344,7 @@
 	}
 #if IDETAPE_DEBUG_LOG
 	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 */
 
 	pc->retries++;
@@ -2321,9 +2368,8 @@
 	OUT_BYTE (bcount.b.low,      IDE_BCOUNTL_REG);
 	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {						/* Begin DMA, if necessary */
+	if (dma_ok) {			/* Will begin DMA later */
 		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)) {
@@ -3086,7 +3132,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3345,11 +3391,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		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;
 	if (tape->merge_stage != NULL) {
 		__idetape_kfree_stage (tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3361,9 +3411,14 @@
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
-	cnt = tape->nr_stages - tape->nr_pending_stages;
-	while (tape->first_stage != NULL)
-		idetape_remove_stage_head (drive);
+	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);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3951,7 +4006,7 @@
 		 */
 		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
 		if (bytes_read < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3963,7 +4018,7 @@
 	rq.cmd = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
-	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
+	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages < max_stages) {
 		new_stage = idetape_kmalloc_stage (tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
@@ -4073,6 +4128,12 @@
 #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
 	 * of the pipeline
 	 */
@@ -4099,14 +4160,7 @@
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		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 {
+	else {
 		idetape_switch_buffers (tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
@@ -4114,7 +4168,8 @@
 				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
 #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);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4478,6 +4533,14 @@
 		tape->restart_speed_control_req = 1;
 		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) {
 		/*
@@ -4485,28 +4548,36 @@
 		 *	filemarks.
 		 */
 		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) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head (drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
+			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);
+				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);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline (drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4515,25 +4586,17 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
+		case MTBSF:
 			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
 			return (idetape_queue_pc_tail (drive, &pc));
 		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:
 			if (!tape->capabilities.sprev)
 				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);
-			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
 			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
@@ -4862,7 +4925,7 @@
 		 */
 		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
 		if (retval < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -5436,9 +5499,11 @@
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
+	if (tape->onstream)
+		idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
@@ -5511,10 +5576,11 @@
 	if (minor < 128)
 		(void) idetape_rewind_tape (drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
 				if (!idetape_queue_pc_tail (drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 		MOD_DEC_USE_COUNT;
 	}
@@ -5548,34 +5614,34 @@
 	printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
 	printk (KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk (KERN_INFO "ATA\n");break;
-		case 2:	printk (KERN_INFO "ATAPI\n");break;
-		case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk ("ATA\n");break;
+		case 2:	printk ("ATAPI\n");break;
+		case 3: printk ("Reserved (Unknown to ide-tape)\n");break;
 	}
 	printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk (KERN_INFO "Direct-access Device\n");break;
-		case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk (KERN_INFO "Reserved\n");break;
-		case 5: printk (KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk (KERN_INFO "Reserved\n");
-		case 7: printk (KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
-		default: printk (KERN_INFO "Reserved\n");
+		case 0: printk ("Direct-access Device\n");break;
+		case 1: printk ("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk ("Reserved\n");break;
+		case 5: printk ("CD-ROM Device\n");break;
+		case 6: printk ("Reserved\n");
+		case 7: printk ("Optical memory Device\n");break;
+		case 0x1f: printk ("Unknown or no Device type\n");break;
+		default: printk ("Reserved\n");
 	}
 	printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
 	printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk ("Microprocessor DRQ\n");break;
+		case 1: printk ("Interrupt DRQ\n");break;
+		case 2: printk ("Accelerated DRQ\n");break;
+		case 3: printk ("Reserved\n");break;
 	}
 	printk (KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk (KERN_INFO "12 bytes\n");break;
-		case 1: printk (KERN_INFO "16 bytes\n");break;
-		default: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk ("12 bytes\n");break;
+		case 1: printk ("16 bytes\n");break;
+		default: printk ("Reserved\n");break;
 	}
 	printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
 	printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
@@ -5591,44 +5657,44 @@
 	printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "%d ",i);
+			printk ("%d ",i);
 		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: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "%d ",i);
+			printk ("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk ("(active) ");
 	}
-	printk (KERN_INFO "\n");
+	printk ("\n");
 	if (id->field_valid & 0x0002) {
 		printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
 		printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk ("Not supported\n");
 		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: ");
 		if (id->eide_dma_time == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk ("Not supported\n");
 		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: ");
 		if (id->eide_pio == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk ("Not supported\n");
 		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: ");
 		if (id->eide_pio_iordy == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk ("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk ("%d ns\n",id->eide_pio_iordy);
 		
 	} else
 		printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
@@ -5937,9 +6003,9 @@
  *			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,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			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_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_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,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			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_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);
@@ -6054,8 +6120,11 @@
 	si_meminfo(&si);
 	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->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = IDE_MIN(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	tape->min_pipeline = IDE_MIN(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+	tape->max_pipeline = IDE_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);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);

[-- Attachment #3: ide-tape patch for 2.5.50 --]
[-- Type: TEXT/PLAIN, Size: 24546 bytes --]

--- linux/drivers/ide/ide-tape.c.orig	Mon Dec  9 14:42:07 2002
+++ linux/drivers/ide/ide-tape.c	Mon Dec  9 14:46:04 2002
@@ -1,5 +1,5 @@
 /*
- * 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>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- 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
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		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/module.h>
@@ -577,9 +599,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	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_INCREASE_STAGES_RATE	 20
 
@@ -601,8 +624,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -1610,24 +1633,6 @@
 	}
 }
 
-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".
  */
@@ -1672,7 +1677,7 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
 #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 = min(tape->max_stages, tape->max_pipeline);
 }
@@ -1745,6 +1750,29 @@
 	}
 }
 
+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
  *	insert a pending pipeline request into the main device queue.
@@ -1756,6 +1784,7 @@
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1780,6 +1809,7 @@
 
 	/* The request was a pipelined data transfer request */
 	if (tape->active_data_request == rq) {
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1802,15 +1832,17 @@
 						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
 				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline(drive);
+					idetape_abort_pipeline(drive, active_stage);
 				if (tape->onstream && !tape->raw &&
 				    error == IDETAPE_ERROR_GENERAL &&
 				    tape->sense.sense_key == 3) {
@@ -1821,14 +1853,16 @@
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->flags == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				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) {
@@ -1879,7 +1913,7 @@
 	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -1980,7 +2014,7 @@
 	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	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,
 			 * if the tape is crossing a filemark during a
@@ -1992,8 +2026,18 @@
 			 * actually transferred (we can't receive that
 			 * 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);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers(pc);
 		}
@@ -2029,7 +2073,7 @@
 		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			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);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2195,6 +2239,10 @@
 		BUG();
 	/* Set the interrupt routine */
 	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 */
 	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
@@ -2223,8 +2271,7 @@
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit(PC_ABORT, &pc->flags)) {
 			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
@@ -2249,7 +2296,7 @@
 	}
 #if IDETAPE_DEBUG_LOG
 	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 */
 
 	pc->retries++;
@@ -2275,9 +2322,8 @@
 	OUT_BYTE(bcount.b.high,     IDE_BCOUNTH_REG);
 	OUT_BYTE(bcount.b.low,      IDE_BCOUNTL_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);
-		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
 		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
@@ -3069,7 +3115,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3333,11 +3379,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		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;
 	if (tape->merge_stage != NULL) {
 		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3349,9 +3399,14 @@
 		idetape_wait_for_request(drive, tape->active_data_request);
 	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);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3946,7 +4001,7 @@
 		 */
 		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
 		if (bytes_read < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3959,7 +4014,7 @@
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
-	    tape->nr_stages <= max_stages) {
+	    tape->nr_stages < max_stages) {
 		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
@@ -4069,6 +4124,12 @@
 #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
 	 * of the pipeline
 	 */
@@ -4097,14 +4158,7 @@
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		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 {
+	else {
 		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
@@ -4112,7 +4166,8 @@
 				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
 #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);
 		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4455,6 +4510,14 @@
 		tape->restart_speed_control_req = 1;
 		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) {
 		/*
@@ -4462,28 +4525,36 @@
 		 *	filemarks.
 		 */
 		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) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head(drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
+			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);
+				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);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline(drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4492,25 +4563,17 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
+		case MTBSF:
 			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
 			return (idetape_queue_pc_tail(drive, &pc));
 		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:
 			if (!tape->capabilities.sprev)
 				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);
-			return (idetape_space_over_filemarks(drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
 			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
@@ -4861,7 +4924,7 @@
 		 */
 		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
 		if (retval < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -5447,8 +5510,10 @@
 		printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
-	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->onstream)
+		idetape_read_position(drive);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
@@ -5520,10 +5585,11 @@
 	if (minor < 128)
 		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
 				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 	}
 	clear_bit(IDETAPE_BUSY, &tape->flags);
@@ -5556,34 +5622,34 @@
 	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
 	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk(KERN_INFO "ATA\n");break;
-		case 2:	printk(KERN_INFO "ATAPI\n");break;
-		case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk(KERN_INFO "Direct-access Device\n");break;
-		case 1: printk(KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break;
-		case 5: printk(KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk(KERN_INFO "Reserved\n");
-		case 7: printk(KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break;
-		default: printk(KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
 	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
 	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk(KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk(KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk(KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk(KERN_INFO "12 bytes\n");break;
-		case 1: printk(KERN_INFO "16 bytes\n");break;
-		default: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
 	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
@@ -5599,45 +5665,45 @@
 	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		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: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk(KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk(KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
 		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
 			id->eide_pio_modes & 1 ? "Mode 3":"None");
 		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_dma_time == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_pio == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		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: ");
 		if (id->eide_pio_iordy == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
 		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
@@ -5946,9 +6012,9 @@
  *			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,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			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_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_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,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			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_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);
@@ -6063,8 +6129,11 @@
 	si_meminfo(&si);
 	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->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	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);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2003-03-08 19:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-03-07 23:00 PATCH for ide-tape driver Frans Pop
2003-03-08 20:01 ` Alan Stern
  -- strict thread matches above, loose matches on Subject: below --
2002-12-09 20:03 Patch " Alan Stern
2002-12-10  0:37 ` Alan Cox
2002-12-10 21:15   ` Alan Stern
2002-12-30 16:34   ` Alan Stern

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).