patch-2.1.8 linux/drivers/block/ide-tape.c

Next file: linux/drivers/block/ide-tape.h
Previous file: linux/drivers/block/ide-probe.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.7/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c	Version 1.8 - ALPHA	Sep  26, 1996
+ * linux/drivers/block/ide-tape.c	Version 1.10 - BETA	Nov   5, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -27,13 +27,16 @@
  * The block device major and minor numbers are determined from the
  * tape's relative position in the ide interfaces, as explained in ide.c.
  *
- * The character device interface consists of two devices:
+ * The character device interface consists of the following devices:
  *
- * ht0		major=37,minor=0	first IDE tape, rewind on close.
- * nht0		major=37,minor=128	first IDE tape, no rewind on close.
+ * ht0		major 37, minor 0	first  IDE tape, rewind on close.
+ * ht1		major 37, minor 1	second IDE tape, rewind on close.
+ * ...
+ * nht0		major 37, minor 128	first  IDE tape, no rewind on close.
+ * nht1		major 37, minor 129	second IDE tape, no rewind on close.
+ * ...
  *
- * Run /usr/src/linux/scripts/MAKEDEV.ide to create the above entries.
- * We currently support only one ide tape drive.
+ * Run linux/scripts/MAKEDEV.ide to create the above entries.
  *
  * The general magnetic tape commands compatible interface, as defined by
  * include/linux/mtio.h, is accessible through the character device.
@@ -49,13 +52,7 @@
  * following scenario:
  *
  *	1.	ide-tape is operating in the pipelined operation mode.
- *	2.	All character device read/write requests consist of an
- *		integral number of the tape's recommended data transfer unit
- *		(which is shown on initialization and can be received with
- *		 an ioctl).
- *		As of version 1.3 of the driver, this is no longer as critical
- *		as it used to be.
- *	3.	No buffering is performed by the user backup program.
+ *	2.	No buffering is performed by the user backup program.
  *
  * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
  * 
@@ -189,15 +186,22 @@
  * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
  * Ver 1.8   Sep 26 96   Attempt to find a better balance between good
  *                        interactive response and high system throughput.
- *
- * We are currently in an *alpha* stage. The driver is not complete and not
- * much tested. I would strongly suggest to:
- *
- *	1. Connect the tape to a separate interface and irq.
- *	2. Be truly prepared for a kernel crash and the resulting data loss.
- *	3. Don't rely too much on the resulting backups.
- *
- * Other than that, enjoy !
+ * Ver 1.9   Nov  5 96   Automatically cross encountered filemarks rather
+ *                        than requiring an explicit FSF command.
+ *                       Abort pending requests at end of media.
+ *                       MTTELL was sometimes returning incorrect results.
+ *                       Return the real block size in the MTIOCGET ioctl.
+ *                       Some error recovery bug fixes.
+ * Ver 1.10  Nov  5 96   Major reorganization.
+ *                       Reduced CPU overhead a bit by eliminating internal
+ *                        bounce buffers.
+ *                       Added module support.
+ *                       Added multiple tape drives support.
+ *                       Added partition support.
+ *                       Rewrote DSC handling.
+ *                       Some portability fixes.
+ *                       Removed ide-tape.h.
+ *                       Additional minor changes.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -280,7 +284,7 @@
  *	pipelined mode might be the best option.
  *
  * You can enable/disable/tune the pipelined operation mode by adjusting
- * the compile time parameters in ide-tape.h.
+ * the compile time parameters below.
  */
 
 /*
@@ -308,7 +312,7 @@
  */
 
 #include <linux/config.h>
-#include <linux/hdreg.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -328,167 +332,443 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/unaligned.h>
+#include <asm/bitops.h>
 
 /*
  *	Main Linux ide driver include file
- *
- *	Automatically includes our include file - ide-tape.h.
  */
- 
-#include "ide.h"		
+#include "ide.h"
 
 /*
- *	Supported ATAPI tape drives packet commands
+ *	For general magnetic tape device compatibility.
  */
+#include <linux/mtio.h>
 
-#define	IDETAPE_TEST_UNIT_READY_CMD	0x00
-#define	IDETAPE_REWIND_CMD		0x01
-#define	IDETAPE_REQUEST_SENSE_CMD	0x03
-#define	IDETAPE_READ_CMD		0x08
-#define	IDETAPE_WRITE_CMD		0x0a
-#define	IDETAPE_WRITE_FILEMARK_CMD	0x10
-#define	IDETAPE_SPACE_CMD		0x11
-#define	IDETAPE_INQUIRY_CMD		0x12
-#define	IDETAPE_ERASE_CMD		0x19
-#define	IDETAPE_MODE_SENSE_CMD		0x1a
-#define	IDETAPE_LOAD_UNLOAD_CMD		0x1b
-#define	IDETAPE_LOCATE_CMD		0x2b
-#define	IDETAPE_READ_POSITION_CMD	0x34
+/**************************** Tunable parameters *****************************/
 
 /*
- *	Some defines for the SPACE command
+ *	Pipelined mode parameters.
+ *
+ *	We try to use the minimum number of stages which is enough to
+ *	keep the tape constantly streaming. To accomplish that, we implement
+ *	a feedback loop around the maximum number of stages:
  *
- *	(The code field in the SPACE packet command).
+ *	We start from MIN maximum stages (we will not even use MIN stages
+ *      if we don't need them), increment it by RATE*(MAX-MIN)
+ *	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.
  */
- 
-#define	IDETAPE_SPACE_OVER_FILEMARK	1
-#define	IDETAPE_SPACE_TO_EOD		3
+#define IDETAPE_MIN_PIPELINE_STAGES	100
+#define IDETAPE_MAX_PIPELINE_STAGES	200
+#define IDETAPE_INCREASE_STAGES_RATE	 20
 
 /*
- *	Some defines for the LOAD UNLOAD command
+ *	Assuming the tape shares an interface with another device, the default
+ *	behavior is to service our pending pipeline requests as soon as
+ *	possible, but to gracefully postpone them in favor of the other device
+ *	when the tape is busy. This has the potential to maximize our
+ *	throughput and in the same time, to make efficient use of the IDE bus.
+ *
+ *	Note that when we transfer data to / from the tape, we co-operate with
+ *	the relatively fast tape buffers and the tape will perform the
+ *	actual media access in the background, without blocking the IDE
+ *	bus. This means that as long as the maximum IDE bus throughput is much
+ *	higher than the sum of our maximum throughput and the maximum
+ *	throughput of the other device, we should probably leave the default
+ *	behavior.
+ *
+ *	However, if it is still desired to give the other device a share even
+ *	in our own (small) bus bandwidth, you can set IDETAPE_LOW_TAPE_PRIORITY
+ *	to 1. This will let the other device finish *all* its pending requests
+ *	before we even check if we can service our next pending request.
  */
- 
-#define	IDETAPE_LU_LOAD_MASK		1
-#define	IDETAPE_LU_RETENSION_MASK	2
-#define	IDETAPE_LU_EOT_MASK		4
+#define IDETAPE_LOW_TAPE_PRIORITY	0
 
 /*
- *	Our ioctls - We will use 0x034n and 0x035n
+ *	The following are used to debug the driver:
+ *
+ *	Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
+ *	Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in
+ *	some places.
+ *
+ *	Setting them to 0 will restore normal operation mode:
  *
- *	Nothing special meanwhile.
- *	mtio.h MTIOCTOP compatible commands are supported on the character
- *	device interface.
+ *		1.	Disable logging normal successful operations.
+ *		2.	Disable self-sanity checks.
+ *		3.	Errors will still be logged, of course.
+ *
+ *	All the #if DEBUG code will be removed some day, when the driver
+ *	is verified to be stable enough. This will make it much more
+ *	esthetic.
  */
+#define IDETAPE_DEBUG_LOG		0
+#define IDETAPE_DEBUG_BUGS		1
 
 /*
- *	Special requests for our block device strategy routine.
- *
- *	In order to service a character device command, we add special
- *	requests to the tail of our block device request queue and wait
- *	for their completion.
+ *	After each failed packet command we issue a request sense command
+ *	and retry the packet command IDETAPE_MAX_PC_RETRIES times.
  *
+ *	Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
  */
+#define IDETAPE_MAX_PC_RETRIES		3
 
-#define	IDETAPE_FIRST_REQUEST			90
+/*
+ *	With each packet command, we allocate a buffer of
+ *	IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet
+ *	commands (Not for READ/WRITE commands).
+ */
+#define IDETAPE_PC_BUFFER_SIZE		256
 
 /*
- * 	IDETAPE_PACKET_COMMAND_REQUEST_TYPE1 is used to queue a packet command
- *	in the request queue. We will wait for DSC before issuing the command
- *	if it is still not set. In that case, we will temporary replace the
- *	cmd field to type 2 and restore it back to type 1 when we receive DSC
- *	and can start with sending the command.
+ *	In various places in the driver, we need to allocate storage
+ *	for packet commands and requests, which will remain valid while
+ *	we leave the driver to wait for an interrupt or a timeout event.
  */
- 
-#define	IDETAPE_PACKET_COMMAND_REQUEST_TYPE1	90
-#define	IDETAPE_PACKET_COMMAND_REQUEST_TYPE2	91
+#define IDETAPE_PC_STACK		(10 + IDETAPE_MAX_PC_RETRIES)
 
 /*
- *	IDETAPE_READ_REQUEST and IDETAPE_WRITE_REQUEST are used by our
- *	character device interface to request read/write operations from
- *	our block device interface.
+ *	DSC polling parameters.
+ *
+ *	Polling for DSC (a single bit in the status register) is a very
+ *	important function in ide-tape. There are two cases in which we
+ *	poll for DSC:
  *
- *	In case a read or write request was requested by the buffer cache
- *	and not by our character device interface, the cmd field in the
- *	request will contain READ and WRITE instead.
+ *	1.	Before a read/write packet command, to ensure that we
+ *		can transfer data from/to the tape's data buffers, without
+ *		causing an actual media access. In case the tape is not
+ *		ready yet, we take out our request from the device
+ *		request queue, so that ide.c will service requests from
+ *		the other device on the same interface meanwhile.
  *
- *	We handle both cases in a similar way. The main difference is that
- *	in our own requests, buffer head is NULL and idetape_end_request
- *	will update the errors field if the request was not completed.
+ *	2.	After the successful initialization of a "media access
+ *		packet command", which is a command which can take a long
+ *		time to complete (it can be several seconds or even an hour).
+ *
+ *		Again, we postpone our request in the middle to free the bus
+ *		for the other device. The polling frequency here should be
+ *		lower than the read/write frequency since those media access
+ *		commands are slow. We start from a "fast" frequency -
+ *		IDETAPE_DSC_MA_FAST (one second), and if we don't receive DSC
+ *		after IDETAPE_DSC_MA_THRESHOLD (5 minutes), we switch it to a
+ *		lower frequency - IDETAPE_DSC_MA_SLOW (1 minute).
+ *
+ *	We also set a timeout for the timer, in case something goes wrong.
+ *	The timeout should be longer then the maximum execution time of a
+ *	tape operation.
+ */
+ 
+/*
+ *	The following parameter is used to select the point in the internal
+ *	tape fifo in which we will start to refill the buffer. Decreasing
+ *	the following parameter will improve the system's latency and
+ *	interactive response, while using a high value might improve sytem
+ *	throughput.
+ */
+#define IDETAPE_FIFO_THRESHOLD 		2
+
+/*
+ *	DSC timings.
  */
+#define IDETAPE_DSC_RW_MIN		5*HZ/100	/* 50 msec */
+#define IDETAPE_DSC_RW_MAX		40*HZ/100	/* 400 msec */
+#define IDETAPE_DSC_RW_TIMEOUT		2*60*HZ		/* 2 minutes */
+#define IDETAPE_DSC_MA_FAST		2*HZ		/* 2 seconds */
+#define IDETAPE_DSC_MA_THRESHOLD	5*60*HZ		/* 5 minutes */
+#define IDETAPE_DSC_MA_SLOW		30*HZ		/* 30 seconds */
+#define IDETAPE_DSC_MA_TIMEOUT		2*60*60*HZ	/* 2 hours */
 
-#define	IDETAPE_READ_REQUEST			92
-#define	IDETAPE_WRITE_REQUEST			93
+/*************************** End of tunable parameters ***********************/
 
-#define IDETAPE_LAST_REQUEST			93
+typedef enum {
+	idetape_direction_none,
+	idetape_direction_read,
+	idetape_direction_write
+} idetape_chrdev_direction_t;
 
 /*
- *	A macro which can be used to check if a we support a given
- *	request command.
+ *	Our view of a packet command.
  */
+typedef struct idetape_packet_command_s {
+	u8 c[12];				/* Actual packet bytes */
+	int retries;				/* On each retry, we increment retries */
+	int error;				/* Error code */
+	int request_transfer;			/* Bytes to transfer */
+	int actually_transferred;		/* Bytes actually transferred */
+	int buffer_size;			/* Size of our data buffer */
+	struct buffer_head *bh;
+	char *b_data;
+	int b_count;
+	byte *buffer;				/* Data buffer */
+	byte *current_position;			/* Pointer into the above buffer */
+	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
+	unsigned int flags;			/* Status/Action bit flags */
+} idetape_pc_t;
 
-#define IDETAPE_REQUEST_CMD(cmd) 	((cmd >= IDETAPE_FIRST_REQUEST) && (cmd <= IDETAPE_LAST_REQUEST))
+/*
+ *	Packet command flag bits.
+ */
+#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
+#define PC_WAIT_FOR_DSC			1	/* 1 When polling for DSC on a media access command */
+#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
+#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
+#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
+#define	PC_WRITING			5	/* Data direction */
 
 /*
- *	We are now able to postpone an idetape request in the stage
- *	where it is polling for DSC and service requests from the other
- *	ide device meanwhile.
+ *	Capabilities and Mechanical Status Page
+ */
+typedef struct {
+	unsigned	page_code	:6;	/* Page code - Should be 0x2a */
+	unsigned	reserved1_67	:2;
+	u8		page_length;		/* Page Length - Should be 0x12 */
+	u8		reserved2, reserved3;
+	unsigned	ro		:1;	/* Read Only Mode */
+	unsigned	reserved4_1234	:4;
+	unsigned	sprev		:1;	/* Supports SPACE in the reverse direction */
+	unsigned	reserved4_67	:2;
+	unsigned	reserved5_012	:3;
+	unsigned	efmt		:1;	/* Supports ERASE command initiated formatting */
+	unsigned	reserved5_4	:1;
+	unsigned	qfa		:1;	/* Supports the QFA two partition formats */
+	unsigned	reserved5_67	:2;
+	unsigned	lock		:1;	/* Supports locking the volume */
+	unsigned	locked		:1;	/* The volume is locked */
+	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */	
+	unsigned	eject		:1;	/* The device can eject the volume */
+	unsigned	reserved6_45	:2;	/* Reserved */	
+	unsigned	ecc		:1;	/* Supports error correction */
+	unsigned	cmprs		:1;	/* Supports data compression */
+	unsigned	reserved7_0	:1;
+	unsigned	blk512		:1;	/* Supports 512 bytes block size */
+	unsigned	blk1024		:1;	/* Supports 1024 bytes block size */
+	unsigned	reserved7_3_6	:4;
+	unsigned	slowb		:1;	/* The device restricts the byte count for PIO */
+						/* transfers for slow buffer memory ??? */
+	u16		max_speed;		/* Maximum speed supported in KBps */
+	u8		reserved10, reserved11;
+	u16		ctl;			/* Continuous Transfer Limit in blocks */
+	u16		speed;			/* Current Speed, in KBps */
+	u16		buffer_size;		/* Buffer Size, in 512 bytes */
+	u8		reserved18, reserved19;
+} idetape_capabilities_page_t;
+
+/*
+ *	A pipeline stage.
+ */
+typedef struct idetape_stage_s {
+	struct request rq;			/* The corresponding request */
+	struct buffer_head *bh;			/* The data buffers */
+	struct idetape_stage_s *next;		/* Pointer to the next stage */
+} idetape_stage_t;
+
+/*
+ *	Most of our global data which we need to save even as we leave the
+ *	driver due to an interrupt or a timer event is stored in a variable
+ *	of type idetape_tape_t, defined below.
  */
+typedef struct {
+	ide_drive_t *drive;
 
-#define	IDETAPE_RQ_POSTPONED		0x1234
+	/*
+	 *	Since a typical character device operation requires more
+	 *	than one packet command, we provide here enough memory
+	 *	for the maximum of interconnected packet commands.
+	 *	The packet commands are stored in the circular array pc_stack.
+	 *	pc_stack_index points to the last used entry, and warps around
+	 *	to the start when we get to the last array entry.
+	 *
+	 *	pc points to the current processed packet command.
+	 *
+	 *	failed_pc points to the last failed packet command, or contains
+	 *	NULL if we do not need to retry any packet command. This is
+	 *	required since an additional packet command is needed before the
+	 *	retry, to get detailed information on what went wrong.
+      	 */
+	idetape_pc_t *pc;			/* Current packet command */
+	idetape_pc_t *failed_pc; 		/* Last failed packet command */
+	idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
+	int pc_stack_index;			/* Next free packet command storage space */
+	struct request rq_stack[IDETAPE_PC_STACK];
+	int rq_stack_index;			/* We implement a circular array */
+
+	/*
+	 *	DSC polling variables.
+	 *
+	 *	While polling for DSC we use postponed_rq to postpone the
+	 *	current request so that ide.c will be able to service
+	 *	pending requests on the other device. Note that at most
+	 *	we will have only one DSC (usually data transfer) request
+	 *	in the device request queue. Additional requests can be
+	 *	queued in our internal pipeline, but they will be visible
+	 *	to ide.c only one at a time.
+	 */
+	struct request *postponed_rq;
+	unsigned long dsc_polling_start;	/* The time in which we started polling for DSC */
+	struct timer_list dsc_timer;		/* Timer used to poll for dsc */
+	unsigned long best_dsc_rw_frequency;	/* Read/Write dsc polling frequency */
+	unsigned long dsc_polling_frequency;	/* The current polling frequency */
+	unsigned long dsc_timeout;		/* Maximum waiting time */
+
+	/*
+	 *	Position information
+	 */
+	byte partition;
+	unsigned int block_address;		/* Current block */
+
+	/*
+	 *	Last error information
+	 */
+	byte sense_key, asc, ascq;
+
+	/*
+	 *	Character device operation
+	 */
+	unsigned int minor;
+	char name[4];					/* device name */
+	idetape_chrdev_direction_t chrdev_direction;	/* Current character device data transfer direction */
+
+	/*
+	 *	Device information
+	 */
+	unsigned short tape_block_size;			/* Usually 512 or 1024 bytes */
+	int user_bs_factor;
+	idetape_capabilities_page_t capabilities;	/* Copy of the tape's Capabilities and Mechanical Page */
+
+	/*
+	 *	Active data transfer request parameters.
+	 *
+	 *	At most, there is only one ide-tape originated data transfer
+	 *	request in the device request queue. This allows ide.c to
+	 *	easily service requests from the other device when we
+	 *	postpone our active request. In the pipelined operation
+	 *	mode, we use our internal pipeline structure to hold
+	 *	more data requests.
+	 *
+	 *	The data buffer size is chosen based on the tape's
+	 *	recommendation.
+	 */
+	struct request *active_data_request;	/* Pointer to the request which is waiting in the device request queue */
+	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
+	idetape_stage_t *merge_stage;
+	int merge_stage_size;
+	struct buffer_head *bh;
+	char *b_data;
+	int b_count;
+	
+	/*
+	 *	Pipeline parameters.
+	 *
+	 *	To accomplish non-pipelined mode, we simply set the following
+	 *	variables to zero (or NULL, where appropriate).
+	 */
+	int nr_stages;				/* Number of currently used stages */
+	int nr_pending_stages;			/* Number of pending stages */
+	int max_stages;				/* We will not allocate more than this number of stages */
+	idetape_stage_t *first_stage;		/* The first stage which will be removed from the pipeline */
+	idetape_stage_t *active_stage;		/* The currently active stage */
+	idetape_stage_t *next_stage;		/* Will be serviced after the currently active request */
+	idetape_stage_t *last_stage;		/* New requests will be added to the pipeline here */
+	idetape_stage_t *cache_stage;		/* Optional free stage which we can use */
+	int pages_per_stage;
+	int excess_bh_size;			/* Wasted space in each stage */
+
+	unsigned int flags;			/* Status/Action flags */
+} idetape_tape_t;
+
+/*
+ *	Tape flag bits values.
+ */
+#define IDETAPE_IGNORE_DSC		0
+#define IDETAPE_ADDRESS_VALID		1	/* 0 When the tape position is unknown */
+#define IDETAPE_BUSY			2	/* Device already opened */
+#define IDETAPE_PIPELINE_ERROR		3	/* Error detected in a pipeline stage */
+#define IDETAPE_DETECT_BS		4	/* Attempt to auto-detect the current user block size */
+#define IDETAPE_FILEMARK		5	/* Currently on a filemark */
 
 /*
- *	Error codes which are returned in rq->errors to the higher part
- *	of the driver.
+ *	Supported ATAPI tape drives packet commands
  */
-
-#define	IDETAPE_RQ_ERROR_GENERAL	1 
-#define	IDETAPE_RQ_ERROR_FILEMARK	2
-#define	IDETAPE_RQ_ERROR_EOD		3
+#define IDETAPE_TEST_UNIT_READY_CMD	0x00
+#define IDETAPE_REWIND_CMD		0x01
+#define IDETAPE_REQUEST_SENSE_CMD	0x03
+#define IDETAPE_READ_CMD		0x08
+#define IDETAPE_WRITE_CMD		0x0a
+#define IDETAPE_WRITE_FILEMARK_CMD	0x10
+#define IDETAPE_SPACE_CMD		0x11
+#define IDETAPE_INQUIRY_CMD		0x12
+#define IDETAPE_ERASE_CMD		0x19
+#define IDETAPE_MODE_SENSE_CMD		0x1a
+#define IDETAPE_LOAD_UNLOAD_CMD		0x1b
+#define IDETAPE_LOCATE_CMD		0x2b
+#define IDETAPE_READ_POSITION_CMD	0x34
 
 /*
- *	ATAPI Task File Registers (Re-definition of the ATA Task File
- *	Registers for an ATAPI packet command).
- * 	From Table 3-2 of QIC-157C.
+ *	Some defines for the SPACE command
  */
+#define IDETAPE_SPACE_OVER_FILEMARK	1
+#define IDETAPE_SPACE_TO_EOD		3
 
-/* Read Access */
+/*
+ *	Some defines for the LOAD UNLOAD command
+ */
+#define IDETAPE_LU_LOAD_MASK		1
+#define IDETAPE_LU_RETENSION_MASK	2
+#define IDETAPE_LU_EOT_MASK		4
 
-#define	IDETAPE_DATA_OFFSET		(0)
-#define IDETAPE_ERROR_OFFSET		(1)
-#define	IDETAPE_IREASON_OFFSET		(2)
-#define IDETAPE_RESERVED3_OFFSET	(3)
-#define IDETAPE_BCOUNTL_OFFSET		(4)
-#define	IDETAPE_BCOUNTH_OFFSET		(5)
-#define IDETAPE_DRIVESEL_OFFSET		(6)
-#define	IDETAPE_STATUS_OFFSET		(7)
+/*
+ *	Special requests for our block device strategy routine.
+ *
+ *	In order to service a character device command, we add special
+ *	requests to the tail of our block device request queue and wait
+ *	for their completion.
+ *
+ */
+#define IDETAPE_FIRST_RQ		90
 
-#define	IDETAPE_DATA_REG		(HWIF(drive)->io_base+IDETAPE_DATA_OFFSET)
-#define IDETAPE_ERROR_REG		(HWIF(drive)->io_base+IDETAPE_ERROR_OFFSET)
-#define	IDETAPE_IREASON_REG		(HWIF(drive)->io_base+IDETAPE_IREASON_OFFSET)
-#define IDETAPE_RESERVED3_REG		(HWIF(drive)->io_base+IDETAPE_RESERVED3_OFFSET)
-#define IDETAPE_BCOUNTL_REG		(HWIF(drive)->io_base+IDETAPE_BCOUNTL_OFFSET)
-#define	IDETAPE_BCOUNTH_REG		(HWIF(drive)->io_base+IDETAPE_BCOUNTH_OFFSET)
-#define IDETAPE_DRIVESEL_REG		(HWIF(drive)->io_base+IDETAPE_DRIVESEL_OFFSET)
-#define	IDETAPE_STATUS_REG		(HWIF(drive)->io_base+IDETAPE_STATUS_OFFSET)
+/*
+ * 	IDETAPE_PC_RQ is used to queue a packet command in the request queue.
+ */
+#define IDETAPE_PC_RQ			90
 
-/* Write Access */
+/*
+ *	IDETAPE_READ_RQ and IDETAPE_WRITE_RQ are used by our
+ *	character device interface to request read/write operations from
+ *	our block device interface.
+ */
+#define IDETAPE_READ_RQ			92
+#define IDETAPE_WRITE_RQ		93
+#define IDETAPE_ABORTED_WRITE_RQ	94
 
-#define	IDETAPE_FEATURES_OFFSET		(1)
-#define IDETAPE_ATACOMMAND_OFFSET	(7)
+#define IDETAPE_LAST_RQ			94
 
-#define IDETAPE_FEATURES_REG		(HWIF(drive)->io_base+IDETAPE_FEATURES_OFFSET)
-#define IDETAPE_ATACOMMAND_REG		(HWIF(drive)->io_base+IDETAPE_ATACOMMAND_OFFSET)
-#define IDETAPE_CONTROL_REG		(HWIF(drive)->ctl_port)
+/*
+ *	A macro which can be used to check if a we support a given
+ *	request command.
+ */
+#define IDETAPE_RQ_CMD(cmd) 		((cmd >= IDETAPE_FIRST_RQ) && (cmd <= IDETAPE_LAST_RQ))
 
+/*
+ *	We are now able to postpone an idetape request in the stage
+ *	where it is polling for DSC and service requests from the other
+ *	ide device meanwhile.
+ */
+#define	IDETAPE_RQ_POSTPONED		0x1234
 
 /*
- *	Structure of the various task file registers
+ *	Error codes which are returned in rq->errors to the higher part
+ *	of the driver.
  */
+#define	IDETAPE_ERROR_GENERAL		101
+#define	IDETAPE_ERROR_FILEMARK		102
+#define	IDETAPE_ERROR_EOD		103
 
 /*
  *	The ATAPI Status Register.
  */
- 
 typedef union {
 	unsigned all			:8;
 	struct {
@@ -496,11 +776,9 @@
 		unsigned idx		:1;	/* Reserved */
 		unsigned corr		:1;	/* Correctable error occurred */
 		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Set when a media access command is finished */
-						/* Reads / Writes are NOT media access commands */
+		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
 		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands */
-						/* (The device is ready to accept ATA command) */
+		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
 		unsigned bsy		:1;	/* The device has access to the command block */
 	} b;
 } idetape_status_reg_t;
@@ -508,7 +786,6 @@
 /*
  *	The ATAPI error register.
  */
- 
 typedef union {
 	unsigned all			:8;
 	struct {
@@ -523,7 +800,6 @@
 /*
  *	ATAPI Feature Register
  */
- 
 typedef union {
 	unsigned all			:8;
 	struct {
@@ -537,7 +813,6 @@
 /*
  *	ATAPI Byte Count Register.
  */
- 
 typedef union {
 	unsigned all			:16;
 	struct {
@@ -549,7 +824,6 @@
 /*
  *	ATAPI Interrupt Reason Register.
  */
- 
 typedef union {
 	unsigned all			:8;
 	struct {
@@ -562,7 +836,6 @@
 /*
  *	ATAPI Drive Select Register
  */
- 
 typedef union {	
 	unsigned all			:8;
 	struct {
@@ -577,7 +850,6 @@
 /*
  *	ATAPI Device Control Register
  */
- 
 typedef union {			
 	unsigned all			:8;
 	struct {
@@ -593,126 +865,91 @@
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
  *	ide_drive_t structure.
- *
- *	We currently support only one tape drive.
- * 
  */
- 
 typedef struct {
 	ide_drive_t *drive;
-	int major,minor;
-	char name[4];
 } idetape_chrdev_t;
 
 /*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
-
 struct idetape_id_gcw {	
-
-	unsigned packet_size	:2;	/* Packet Size */
-	unsigned reserved2	:1;	/* Reserved */
-	unsigned reserved3	:1;	/* Reserved */
-	unsigned reserved4	:1;	/* Reserved */
-	unsigned drq_type	:2;	/* Command packet DRQ type */
-	unsigned removable	:1;	/* Removable media */
-	unsigned device_type	:5;	/* Device type */
-	unsigned reserved13	:1;	/* Reserved */
-	unsigned protocol	:2;	/* Protocol type */
+	unsigned packet_size		:2;	/* Packet Size */
+	unsigned reserved234		:3;	/* Reserved */
+	unsigned drq_type		:2;	/* Command packet DRQ type */
+	unsigned removable		:1;	/* Removable media */
+	unsigned device_type		:5;	/* Device type */
+	unsigned reserved13		:1;	/* Reserved */
+	unsigned protocol		:2;	/* Protocol type */
 };
 
 /*
  *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
  */
- 
 typedef struct {
-	unsigned device_type	:5;	/* Peripheral Device Type */
-	unsigned reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
-	unsigned reserved1_6t0	:7;	/* Reserved */
-	unsigned rmb		:1;	/* Removable Medium Bit */
-	unsigned ansi_version	:3;	/* ANSI Version */
-	unsigned ecma_version	:3;	/* ECMA Version */
-	unsigned iso_version	:2;	/* ISO Version */
-	unsigned response_format :4;	/* Response Data Format */
-	unsigned reserved3_45	:2;	/* Reserved */
-	unsigned reserved3_6	:1;	/* TrmIOP - Reserved */
-	unsigned reserved3_7	:1;	/* AENC - Reserved */
-	byte additional_length;		/* Additional Length (total_length-4) */
-	byte reserved_5;		/* Reserved */
-	byte reserved_6;		/* Reserved */
-	unsigned reserved7_0	:1;	/* SftRe - Reserved */
-	unsigned reserved7_1	:1;	/* CmdQue - Reserved */
-	unsigned reserved7_2	:1;	/* Reserved */
-	unsigned reserved7_3	:1;	/* Linked - Reserved */
-	unsigned reserved7_4	:1;	/* Sync - Reserved */
-	unsigned reserved7_5	:1;	/* WBus16 - Reserved */
-	unsigned reserved7_6	:1;	/* WBus32 - Reserved */
-	unsigned reserved7_7	:1;	/* RelAdr - Reserved */
-	byte vendor_id [8];		/* Vendor Identification */
-	byte product_id [16];		/* Product Identification */
-	byte revision_level [4];	/* Revision Level */
-	byte vendor_specific [20];	/* Vendor Specific - Optional */
-	byte reserved56t95 [40];	/* Reserved - Optional */
-	
-					/* Additional information may be returned */
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	response_format :4;	/* Response Data Format */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+	u8		additional_length;	/* Additional Length (total_length-4) */
+	u8		rsv5, rsv6, rsv7;	/* Reserved */
+	u8		vendor_id[8];		/* Vendor Identification */
+	u8		product_id[16];		/* Product Identification */
+	u8		revision_level[4];	/* Revision Level */
+	u8		vendor_specific[20];	/* Vendor Specific - Optional */
+	u8		reserved56t95[40];	/* Reserved - Optional */
+						/* Additional information may be returned */
 } idetape_inquiry_result_t;
 
 /*
  *	READ POSITION packet command - Data Format (From Table 6-57)
  */
- 
 typedef struct {
-	unsigned reserved0_10	:2;	/* Reserved */
-	unsigned bpu		:1;	/* Block Position Unknown */	
-	unsigned reserved0_543	:3;	/* Reserved */
-	unsigned eop		:1;	/* End Of Partition */
-	unsigned bop		:1;	/* Beginning Of Partition */
-	byte partition_num;		/* Partition Number */
-	byte reserved_2;		/* Reserved */
-	byte reserved_3;		/* Reserved */
-	unsigned long first_block;	/* First Block Location */
-	unsigned long last_block;	/* Last Block Location (Optional) */
-	byte reserved_12;		/* Reserved */
-	byte blocks_in_buffer_2;	/* Blocks In Buffer - MSB (Optional) */
-	byte blocks_in_buffer_1;
-	byte blocks_in_buffer_0;	/* Blocks In Buffer - LSB (Optional) */
-	unsigned long bytes_in_buffer;	/* Bytes In Buffer (Optional) */
+	unsigned	reserved0_10	:2;	/* Reserved */
+	unsigned	bpu		:1;	/* Block Position Unknown */	
+	unsigned	reserved0_543	:3;	/* Reserved */
+	unsigned	eop		:1;	/* End Of Partition */
+	unsigned	bop		:1;	/* Beginning Of Partition */
+	u8		partition;		/* Partition Number */
+	u8		reserved2, reserved3;	/* Reserved */
+	u32		first_block;		/* First Block Location */
+	u32		last_block;		/* Last Block Location (Optional) */
+	u8		reserved12;		/* Reserved */
+	u8		blocks_in_buffer[3];	/* Blocks In Buffer - (Optional) */
+	u32		bytes_in_buffer;	/* Bytes In Buffer (Optional) */
 } idetape_read_position_result_t;
 
 /*
  *	REQUEST SENSE packet command result - Data Format.
  */
-
 typedef struct {
-	unsigned error_code	:7;	/* Current of deferred errors */
-	unsigned valid		:1;	/* The information field conforms to QIC-157C */
-	unsigned reserved_1	:8;	/* Segment Number - Reserved */
-	unsigned sense_key	:4;	/* Sense Key */
-	unsigned reserved2_4	:1;	/* Reserved */
-	unsigned ili		:1;	/* Incorrect Length Indicator */
-	unsigned eom		:1;	/* End Of Medium */
-	unsigned filemark 	:1;	/* Filemark */
-
-	/*
-	 *	We can't use a 32 bit variable, since it will be re-aligned
-	 *	by GCC, as we are not on a 32 bit boundary.
-	 */
-
-	byte information1;		/* MSB - Information - Command specific */
-	byte information2;
-	byte information3;
-	byte information4;		/* LSB */
-	byte asl;			/* Additional sense length (n-7) */
-	unsigned long command_specific; /* Additional command specific information */
-	byte asc;			/* Additional Sense Code */
-	byte ascq;			/* Additional Sense Code Qualifier */
-	byte replaceable_unit_code;	/* Field Replaceable Unit Code */
-	unsigned sk_specific1 	:7;	/* Sense Key Specific */
-	unsigned sksv		:1;	/* Sense Key Specific information is valid */
-	byte sk_specific2;		/* Sense Key Specific */
-	byte sk_specific3;		/* Sense Key Specific */
-	byte pad [2];			/* Padding to 20 bytes */
+	unsigned	error_code	:7;	/* Current of deferred errors */
+	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+	u8		reserved1	:8;	/* Segment Number - Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	eom		:1;	/* End Of Medium */
+	unsigned	filemark 	:1;	/* Filemark */
+	u32		information __attribute__ ((packed));
+	u8		asl;			/* Additional sense length (n-7) */
+	u32		command_specific;	/* Additional command specific information */
+	u8		asc;			/* Additional Sense Code */
+	u8		ascq;			/* Additional Sense Code Qualifier */
+	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
+	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+	u8		sk_specific2;		/* Sense Key Specific */
+	u8		sk_specific3;		/* Sense Key Specific */
+	u8		pad[2];			/* Padding to 20 bytes */
 } idetape_request_sense_result_t;
 
 /*
@@ -720,19 +957,16 @@
  *	packet commands. Those packet commands are still not supported
  *	by ide-tape.
  */
-
 #define	IDETAPE_CAPABILITIES_PAGE	0x2a
 
 /*
  *	Mode Parameter Header for the MODE SENSE packet command
  */
-
 typedef struct {
-	byte mode_data_length;		/* The length of the following data that is */
-					/* available to be transferred */
-	byte medium_type;		/* Medium Type */
-	byte dsp;			/* Device Specific Parameter */
-	byte bdl;			/* Block Descriptor Length */
+	u8		mode_data_length;	/* Length of the following data transfer */
+	u8		medium_type;		/* Medium Type */
+	u8		dsp;			/* Device Specific Parameter */
+	u8		bdl;			/* Block Descriptor Length */
 } idetape_mode_parameter_header_t;
 
 /*
@@ -740,1708 +974,684 @@
  *
  *	Support for block descriptors is optional.
  */
-
 typedef struct {
-	byte density_code;		/* Medium density code */
-	byte blocks1;			/* Number of blocks - MSB */
-	byte blocks2;			/* Number of blocks - Middle byte */
-	byte blocks3;			/* Number of blocks - LSB */
-	byte reserved4;			/* Reserved */
-	byte length1;			/* Block Length - MSB */
-	byte length2;			/* Block Length - Middle byte */
-	byte length3;			/* Block Length - LSB */
+	u8		density_code;		/* Medium density code */
+	u8		blocks[3];		/* Number of blocks */
+	u8		reserved4;		/* Reserved */
+	u8		length[3];		/* Block Length */
 } idetape_parameter_block_descriptor_t;
 
 /*
  *	The Data Compression Page, as returned by the MODE SENSE packet command.
  */
- 
 typedef struct {
-	unsigned page_code	:6;	/* Page Code - Should be 0xf */
-	unsigned reserved	:1;	/* Reserved */
-	unsigned ps		:1;
-	byte page_length;		/* Page Length - Should be 14 */
-	unsigned reserved2	:6;	/* Reserved */
-	unsigned dcc		:1;	/* Data Compression Capable */
-	unsigned dce		:1;	/* Data Compression Enable */
-	unsigned reserved3	:5;	/* Reserved */
-	unsigned red		:2;	/* Report Exception on Decompression */
-	unsigned dde		:1;	/* Data Decompression Enable */
-	unsigned long ca;		/* Compression Algorithm */
-	unsigned long da;		/* Decompression Algorithm */
-	byte reserved_12;		/* Reserved */
-	byte reserved_13;		/* Reserved */
-	byte reserved_14;		/* Reserved */
-	byte reserved_15;		/* Reserved */
+	unsigned	page_code	:6;	/* Page Code - Should be 0xf */
+	unsigned	reserved0	:1;	/* Reserved */
+	unsigned	ps		:1;
+	u8		page_length;		/* Page Length - Should be 14 */
+	unsigned	reserved2	:6;	/* Reserved */
+	unsigned	dcc		:1;	/* Data Compression Capable */
+	unsigned	dce		:1;	/* Data Compression Enable */
+	unsigned	reserved3	:5;	/* Reserved */
+	unsigned	red		:2;	/* Report Exception on Decompression */
+	unsigned	dde		:1;	/* Data Decompression Enable */
+	u32		ca;			/* Compression Algorithm */
+	u32		da;			/* Decompression Algorithm */
+	u8		reserved[4];		/* Reserved */
 } idetape_data_compression_page_t;
 
 /*
  *	The Medium Partition Page, as returned by the MODE SENSE packet command.
  */
-
 typedef struct {
-	unsigned page_code	:6;	/* Page Code - Should be 0x11 */
-	unsigned reserved1_6	:1;	/* Reserved */
-	unsigned ps		:1;
-	byte page_length;		/* Page Length - Should be 6 */
-	byte map;			/* Maximum Additional Partitions - Should be 0 */
-	byte apd;			/* Additional Partitions Defined - Should be 0 */
-	unsigned reserved4_012	:3;	/* Reserved */
-	unsigned psum		:2;	/* Should be 0 */
-	unsigned idp		:1;	/* Should be 0 */
-	unsigned sdp		:1;	/* Should be 0 */
-	unsigned fdp		:1;	/* Fixed Data Partitions */
-	byte mfr;			/* Medium Format Recognition */
-	byte reserved6;			/* Reserved */
-	byte reserved7;			/* Reserved */
+	unsigned	page_code	:6;	/* Page Code - Should be 0x11 */
+	unsigned	reserved1_6	:1;	/* Reserved */
+	unsigned	ps		:1;
+	u8		page_length;		/* Page Length - Should be 6 */
+	u8		map;			/* Maximum Additional Partitions - Should be 0 */
+	u8		apd;			/* Additional Partitions Defined - Should be 0 */
+	unsigned	reserved4_012	:3;	/* Reserved */
+	unsigned	psum		:2;	/* Should be 0 */
+	unsigned	idp		:1;	/* Should be 0 */
+	unsigned	sdp		:1;	/* Should be 0 */
+	unsigned	fdp		:1;	/* Fixed Data Partitions */
+	u8		mfr;			/* Medium Format Recognition */
+	u8		reserved[2];		/* Reserved */
 } idetape_medium_partition_page_t;
 
-/*
- *	Prototypes of various functions in ide-tape.c
- *
- *	The following functions are called from ide.c, and their prototypes
- *	are available in ide.h:
- *
- *		idetape_identify_device
- *		idetape_setup
- *		idetape_blkdev_ioctl
- *		idetape_do_request
- *		idetape_blkdev_open
- *		idetape_blkdev_release
- *		idetape_register_chrdev (void);
- */
-
-/*
- *	The following functions are used to transfer data from / to the
- *	tape's data register.
- */
- 
-void idetape_input_data (ide_drive_t *drive,void *buffer, unsigned long bcount);
-void idetape_output_data (ide_drive_t *drive,void *buffer, unsigned long bcount);
-void idetape_discard_data (ide_drive_t *drive, unsigned long bcount);
-
-/*
- *	Packet command related functions.
- */
- 
-void idetape_issue_packet_command  (ide_drive_t *drive,idetape_packet_command_t *pc,ide_handler_t *handler);
-void idetape_pc_intr (ide_drive_t *drive);
+#define IDETAPE_MIN(a,b)	((a)<(b) ? (a):(b))
+#define	IDETAPE_MAX(a,b)	((a)>(b) ? (a):(b))
 
 /*
- *	DSC handling functions.
+ *	Run time configurable parameters.
  */
- 
-void idetape_postpone_request (ide_drive_t *drive);
-void idetape_poll_for_dsc (unsigned long data);
-void idetape_poll_for_dsc_direct (unsigned long data);
-void idetape_put_back_postponed_request (ide_drive_t *drive);
-void idetape_media_access_finished (ide_drive_t *drive);
+typedef struct {
+	int	dsc_rw_frequency;
+	int	dsc_media_access_frequency;
+	int	nr_stages;
+} idetape_config_t;
 
 /*
- *	Some more packet command related functions.
+ *	The variables below are used for the character device interface.
+ *	Additional state variables are defined in our ide_drive_t structure.
  */
- 
-void idetape_pc_callback (ide_drive_t *drive);
-void idetape_retry_pc (ide_drive_t *drive);
-void idetape_zero_packet_command (idetape_packet_command_t *pc);
-void idetape_queue_pc_head (ide_drive_t *drive,idetape_packet_command_t *pc,struct request *rq);
-void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result);
-
-idetape_packet_command_t *idetape_next_pc_storage (ide_drive_t *drive);
-struct request *idetape_next_rq_storage (ide_drive_t *drive);
+static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
+static int idetape_chrdev_present = 0;
 
 /*
- *	Various packet commands
- */
- 
-void idetape_create_inquiry_cmd (idetape_packet_command_t *pc);
-void idetape_inquiry_callback (ide_drive_t *drive);
-void idetape_create_locate_cmd (idetape_packet_command_t *pc,unsigned long block,byte partition);
-void idetape_create_rewind_cmd (idetape_packet_command_t *pc);
-void idetape_create_write_filemark_cmd (idetape_packet_command_t *pc,int write_filemark);
-void idetape_create_load_unload_cmd (idetape_packet_command_t *pc,int cmd);
-void idetape_create_space_cmd (idetape_packet_command_t *pc,long count,byte cmd);
-void idetape_create_erase_cmd (idetape_packet_command_t *pc);
-void idetape_create_test_unit_ready_cmd (idetape_packet_command_t *pc);
-void idetape_create_read_position_cmd (idetape_packet_command_t *pc);
-void idetape_read_position_callback (ide_drive_t *drive);
-void idetape_create_read_cmd (idetape_packet_command_t *pc,unsigned long length);
-void idetape_read_callback (ide_drive_t *drive);
-void idetape_create_write_cmd (idetape_packet_command_t *pc,unsigned long length);
-void idetape_write_callback (ide_drive_t *drive);
-void idetape_create_request_sense_cmd (idetape_packet_command_t *pc);
-void idetape_create_mode_sense_cmd (idetape_packet_command_t *pc,byte page_code);
-void idetape_request_sense_callback (ide_drive_t *drive);
-
-void idetape_display_inquiry_result (byte *buffer);
-
-/*
- *	Character device callback functions.
- *
- *	We currently support:
- *
- *		OPEN, RELEASE, READ, WRITE and IOCTL.
- */
-
-int idetape_chrdev_read (struct inode *inode, struct file *file, char *buf, int count);
-int idetape_chrdev_write (struct inode *inode, struct file *file, const char *buf, int count);
-int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-int idetape_chrdev_open (struct inode *inode, struct file *file);
-void idetape_chrdev_release (struct inode *inode,struct file *file);
-
-/*
- *	idetape_mtioctop implements general magnetic tape io control
- *	commands, as defined in include/linux/mtio.h. Those commands are
- *	accessed through the character device interface, using the MTIOCTOP
- *	ioctl.
+ *	Too bad. The drive wants to send us data which we are not ready to accept.
+ *	Just throw it away.
  */
- 
-int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count);
+static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		IN_BYTE (IDE_DATA_REG);
+}
 
-/*
- *	idetape_space_over_filemarks handles the MTFSF, MTFSFM, ... mtio.h
- *	commands.
- */
- 
-int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count);
+static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+{
+	struct buffer_head *bh = pc->bh;
+	int count;
+	
+	while (bcount) {
+#if IDETAPE_DEBUG_BUGS
+		if (bh == NULL) {
+			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+			idetape_discard_data (drive, bcount);
+			return;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = IDETAPE_MIN (bh->b_size - bh->b_count, bcount);
+		atapi_input_bytes (drive, bh->b_data + bh->b_count, count);
+		bcount -= count; bh->b_count += count;
+		if (bh->b_count == bh->b_size) {
+			bh = bh->b_reqnext;
+			if (bh)
+				bh->b_count = 0;
+		}
+	}
+	pc->bh = bh;
+}
 
-/*
- *	idetape_add_chrdev_read_request is called from idetape_chrdev_read
- *	to service a character device read request and add read-ahead
- *	requests to our pipeline.
- */
- 
-int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks,char *buffer);
+static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+{
+	struct buffer_head *bh = pc->bh;
+	int count;
+	
+	while (bcount) {
+#if IDETAPE_DEBUG_BUGS
+		if (bh == NULL) {
+			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+			return;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = IDETAPE_MIN (pc->b_count, bcount);
+		atapi_output_bytes (drive, pc->b_data, count);
+		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		if (!pc->b_count) {
+			pc->bh = bh = bh->b_reqnext;
+			if (bh) {
+				pc->b_data = bh->b_data;
+				pc->b_count = bh->b_count;
+			}
+		}
+	}
+}
 
-/*
- *	idetape_add_chrdev_write_request adds a character device write
- *	request to the pipeline.
- */
- 
-int idetape_add_chrdev_write_request (ide_drive_t *drive,int blocks,char *buffer);
+#ifdef CONFIG_BLK_DEV_TRITON
+static void idetape_update_buffers (idetape_pc_t *pc)
+{
+	struct buffer_head *bh = pc->bh;
+	int count, bcount = pc->actually_transferred;
 
-/*
- *	idetape_queue_rw_tail will add a command to the tail of the device
- *	request queue and wait for it to finish. This is used when we
- *	can not allocate pipeline stages (or in non-pipelined mode).
- */
- 
-int idetape_queue_rw_tail (ide_drive_t *drive,int cmd,int blocks,char *buffer);
+	if (test_bit (PC_WRITING, &pc->flags))
+		return;
+	while (bcount) {
+#if IDETAPE_DEBUG_BUGS
+		if (bh == NULL) {
+			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+			return;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = IDETAPE_MIN (bh->b_size, bcount);
+		bh->b_count = count;
+		if (bh->b_count == bh->b_size)
+			bh = bh->b_reqnext;
+		bcount -= count;
+	}
+	pc->bh = bh;
+}
+#endif /* CONFIG_BLK_DEV_TRITON */
 
 /*
- *	Adds a packet command request to the tail of the device request
- *	queue and waits for it to be serviced.
+ *	idetape_poll_for_dsc gets invoked by a timer (which was set
+ *	by idetape_postpone_request) to reinsert our postponed request
+ *	into the request queue.
+ *
+ * 	Note that the procedure done here is different than the method
+ *	we are using in idetape_queue_pc_head - There we are putting
+ *	request(s) before our currently called request.
+ *
+ *	Here, on the other hand, HWGROUP(drive)->rq is not our request
+ *	but rather a request to another device. Therefore, we will let
+ *	it finish and only then service our postponed request --> We don't
+ *	touch HWGROUP(drive)->rq.
  */
- 
-int idetape_queue_pc_tail (ide_drive_t *drive,idetape_packet_command_t *pc);
+static void idetape_poll_for_dsc (unsigned long data)
+{
+	ide_drive_t *drive=(ide_drive_t *) data;
+	idetape_tape_t *tape = drive->driver_data;
 
-int idetape_position_tape (ide_drive_t *drive,unsigned long block);
-int idetape_rewind_tape (ide_drive_t *drive);
-int idetape_flush_tape_buffers (ide_drive_t *drive);
+	del_timer (&tape->dsc_timer);
 
-/*
- *	Used to get device information
- */
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "ide-tape: Putting back postponed request\n");
+#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+	if (tape->postponed_rq == NULL) {
+		printk (KERN_ERR "tape->postponed_rq is NULL in idetape_poll_for_dsc\n");
+		return;
+	}
+#endif /* IDETAPE_DEBUG_BUGS */
 
-void idetape_get_mode_sense_results (ide_drive_t *drive);
+	(void) ide_do_drive_cmd (drive, tape->postponed_rq, ide_next);
+}
 
 /*
- *	General utility functions
+ *	idetape_postpone_request postpones the current request so that
+ *	ide.c will be able to service requests from another device on
+ *	the same hwgroup while we are polling for DSC.
  */
- 
-unsigned long idetape_swap_long (unsigned long temp);
-unsigned short idetape_swap_short (unsigned short temp);
+static void idetape_postpone_request (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	struct request *rq;
+	
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Reached idetape_postpone_request\n");
+#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+	if (tape->postponed_rq != NULL)
+		printk (KERN_ERR "ide-tape.c bug - postponed_rq not NULL in idetape_postpone_request\n");
+#endif /* IDETAPE_DEBUG_BUGS */
 
-#define IDETAPE_MIN(a,b)	((a)<(b) ? (a):(b))
+	/*
+	 *	Set the timer parameters.
+	 */
+	tape->dsc_timer.expires=jiffies + tape->dsc_polling_frequency;
+	tape->dsc_timer.data=(unsigned long) drive;
+	tape->dsc_timer.function = &idetape_poll_for_dsc;
+	init_timer (&tape->dsc_timer);
 
-/*
- *	Pipeline related functions
- */
+	/*
+	 * Remove current request from the request queue:
+	 */
+	tape->postponed_rq = rq = HWGROUP(drive)->rq;
+	rq->rq_status = IDETAPE_RQ_POSTPONED;
+	blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next;
+	HWGROUP(drive)->rq = NULL;
 
-idetape_pipeline_stage_t *idetape_kmalloc_stage (ide_drive_t *drive);
-void idetape_kfree_stage (idetape_pipeline_stage_t *stage);
-void idetape_copy_buffer_from_stage (idetape_pipeline_stage_t *stage,char *buffer);
-void idetape_copy_buffer_to_stage (idetape_pipeline_stage_t *stage,char *buffer);
-void idetape_increase_max_pipeline_stages (ide_drive_t *drive);
-void idetape_add_stage_tail (ide_drive_t *drive,idetape_pipeline_stage_t *stage);
-void idetape_remove_stage_head (ide_drive_t *drive);
-void idetape_active_next_stage (ide_drive_t *drive);
-void idetape_wait_for_pipeline (ide_drive_t *drive);
-void idetape_discard_read_pipeline (ide_drive_t *drive);
-void idetape_empty_write_pipeline (ide_drive_t *drive);
-void idetape_insert_pipeline_into_queue (ide_drive_t *drive);
+	add_timer(&tape->dsc_timer);		/* Activate the polling timer */
+}
 
 /*
- *	For general magnetic tape device compatibility.
- */
- 
-#include <linux/mtio.h>
-
-/*
- *	Global variables
- *
- *	The variables below are used for the character device interface.
- *
- *	Additional state variables are defined in our ide_drive_t structure.
- */
- 
-idetape_chrdev_t idetape_chrdev;		/* Character device interface information */
-byte idetape_drive_already_found=0;		/* 1 when the above data structure is initialized */
-
-/*
- *	Our character device supporting functions, passed to register_chrdev.
- */
- 
-static struct file_operations idetape_fops = {
-	NULL,			/* lseek - default */
-	idetape_chrdev_read,	/* read  */
-	idetape_chrdev_write,	/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* select */
-	idetape_chrdev_ioctl,	/* ioctl */
-	NULL,			/* mmap */
-	idetape_chrdev_open,	/* open */
-	idetape_chrdev_release,	/* release */
-	NULL,			/* fsync */
-	NULL,			/* fasync */
-	NULL,			/* check_media_change */
-	NULL			/* revalidate */
-};
-
-
-/*
- *	idetape_identify_device is called by do_identify in ide.c during
- *	the device probing stage to check the contents of the ATAPI IDENTIFY
- *	command results, in case the device type is tape. We return:
- *
- *	1	If the tape can be supported by us, based on the information
- *		we have so far.
- *
- *	0 	If this tape driver is not currently supported by us.
- *
- *	In case we decide to support the tape, we store the current drive
- *	pointer in our character device global variables, so that we can
- *	pass between both interfaces.
- */
- 
-int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
-
-{
-	struct idetape_id_gcw gcw;
-	unsigned short *ptr;
-	int support=1;
-#if IDETAPE_DEBUG_LOG
-	unsigned short mask,i;
-#endif /* IDETAPE_DEBUG_LOG */
-		
-	ptr=(unsigned short *) &gcw;
-	*ptr=id->config;
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Dumping ATAPI Identify Device tape parameters\n");
-	
-	printk ("Protocol Type: ");
-	switch (gcw.protocol) {
-		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 ("Device Type: %x - ",gcw.device_type);	
-	switch (gcw.device_type) {
-		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 ("Removable: %s",gcw.removable ? "Yes\n":"No\n");	
-		
-	printk ("Command Packet DRQ Type: ");
-	switch (gcw.drq_type) {
-		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 ("Command Packet Size: ");
-	switch (gcw.packet_size) {
-		case 0: printk ("12 bytes\n");break;
-		case 1: printk ("16 bytes\n");break;
-		default: printk ("Reserved\n");break;
-	}
-	printk ("Model: %s\n",id->model);
-	printk ("Firmware Revision: %s\n",id->fw_rev);
-	printk ("Serial Number: %s\n",id->serial_no);
-	printk ("Write buffer size: %d bytes\n",id->buf_size*512);
-	printk ("DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk ("LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk ("IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk ("IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk ("ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk ("PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk ("DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk ("Single Word DMA supported modes: ");
-	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
-		if (id->dma_1word & mask)
-			printk ("%d ",i);
-		if (id->dma_1word & (mask << 8))
-			printk ("(active) ");
-	}
-	printk ("\n");
-
-	printk ("Multi Word DMA supported modes: ");
-	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
-		if (id->dma_mword & mask)
-			printk ("%d ",i);
-		if (id->dma_mword & (mask << 8))
-			printk ("(active) ");
-	}
-	printk ("\n");
-
-	if (id->field_valid & 0x0002) {
-		printk ("Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
-		printk ("Minimum Multi-word DMA cycle per word: ");
-		if (id->eide_dma_min == 0)
-			printk ("Not supported\n");
-		else
-			printk ("%d ns\n",id->eide_dma_min);
-
-		printk ("Manufacturer\'s Recommended Multi-word cycle: ");
-		if (id->eide_dma_time == 0)
-			printk ("Not supported\n");
-		else
-			printk ("%d ns\n",id->eide_dma_time);
-
-		printk ("Minimum PIO cycle without IORDY: ");
-		if (id->eide_pio == 0)
-			printk ("Not supported\n");
-		else
-			printk ("%d ns\n",id->eide_pio);
-
-		printk ("Minimum PIO cycle with IORDY: ");
-		if (id->eide_pio_iordy == 0)
-			printk ("Not supported\n");
-		else
-			printk ("%d ns\n",id->eide_pio_iordy);
-		
-	}
-
-	else {
-		printk ("According to the device, fields 64-70 are not valid.\n");
-	}
-#endif /* IDETAPE_DEBUG_LOG */
-
-	/* Check that we can support this device */
-
-	if (gcw.protocol !=2 ) {
-		printk ("ide-tape: Protocol is not ATAPI\n");support=0;
-	}
-
-	if (gcw.device_type != 1) {
-		printk ("ide-tape: Device type is not set to tape\n");support=0;
-	}
-
-	if (!gcw.removable) {
-		printk ("ide-tape: The removable flag is not set\n");support=0;
-	}
-
-	if (gcw.drq_type != 2) {
-		printk ("ide-tape: Sorry, DRQ types other than Accelerated DRQ\n");
-		printk ("ide-tape: are still not supported by the driver\n");support=0;
-	}
-
-	if (gcw.packet_size != 0) {
-		printk ("ide-tape: Packet size is not 12 bytes long\n");
-		if (gcw.packet_size == 1)
-			printk ("ide-tape: Sorry, padding to 16 bytes is still not supported\n");
-		support=0;			
-	}
-
-	if (idetape_drive_already_found) {
-		printk ("ide-tape: Sorry, only one ide tape drive is supported by the driver\n");
-		support=0;
-	}
-	else {
-		idetape_drive_already_found=1;
-		idetape_chrdev.drive=drive;
-		idetape_chrdev.major=IDETAPE_MAJOR;
-		idetape_chrdev.minor=0;
-		idetape_chrdev.name[0]='h';
-		idetape_chrdev.name[1]='t';
-		idetape_chrdev.name[2]='0';
-		idetape_chrdev.name[3]=0;
-	}
-
-	return (support);		/* In case support=0, we will not install the driver */
-}
-
-/*
- *	idetape_register_chrdev calls register_chrdev to register our character
- *	device interface. The connection to the ide_drive_t structure, which
- *	is used by the entire ide driver is provided by our global variable
- *	idetape_chrdev.drive, which was initialized earlier, during the device
- *	probing stage.
- */
- 
-void idetape_register_chrdev (void)
-
-{
-	int major,minor;
-	ide_drive_t *drive;
-
-	if (!idetape_drive_already_found)
-		return;
-
-	drive=idetape_chrdev.drive;
-	major=idetape_chrdev.major;
-	minor=idetape_chrdev.minor;
-	
-	if (register_chrdev (major,idetape_chrdev.name,&idetape_fops)) {
-		printk ("Unable to register character device interface !\n");
-		/* ??? */
-	}
-	else {
-		printk ("ide-tape: %s <-> %s : Character device interface on major = %d\n",
-			drive->name,idetape_chrdev.name,major);
-	}
-}
-
-/*
- *	idetape_setup is called from the ide driver in the partition table
- *	identification stage, to:
- *
- *		1.	Initialize our various state variables.
- *		2.	Ask the tape for its capabilities.
- *		3.	Allocate a buffer which will be used for data
- *			transfer. The buffer size is chosen based on
- *			the recommendation which we received in step (2).
- *
- *	Note that at this point ide.c already assigned us an irq, so that
- *	we can queue requests here and wait for their completion.
- */
- 
-void idetape_setup (ide_drive_t *drive)
-
-{
-	idetape_tape_t *tape=&(drive->tape);
-	unsigned int allocation_length;
-#if IDETAPE_ANTICIPATE_READ_WRITE_DSC
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long t1, tmid, tn;
-#endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
-
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Reached idetape_setup\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-	
-	drive->ready_stat = 0;			/* With an ATAPI device, we can issue packet commands */
-						/* regardless of the state of DRDY */
-	HWIF(drive)->tape_drive=drive;
-
-	tape->block_address=0;			
-	tape->block_address_valid=0;
-	tape->pc_stack_index=0;
-	tape->failed_pc=NULL;
-	tape->postponed_rq=NULL;
-	tape->busy=0;
-	tape->active_data_request=NULL;
-	tape->current_number_of_stages=0;
-	tape->first_stage=tape->next_stage=tape->last_stage=NULL;
-	tape->error_in_pipeline_stage=0;
-	tape->request_status=0;
-	tape->chrdev_direction=idetape_direction_none;
-	tape->reset_issued=0;
-	tape->pc=&(tape->pc_stack [0]);
-	
-#if IDETAPE_PIPELINE
-	tape->max_number_of_stages=IDETAPE_MIN_PIPELINE_STAGES;
-	printk ("ide-tape: Operating in pipelined (fast and tricky) operation mode.\n");
-#else
-	tape->max_number_of_stages=0;
-	printk ("ide-tape: Operating in non-pipelined (slow and safe) operation mode.\n");
-#endif /* IDETAPE_PIPELINE */
-
-	idetape_get_mode_sense_results (drive);
-
-	tape->data_buffer_size = tape->capabilities.ctl * tape->tape_block_size;
-	while (tape->data_buffer_size > 0xffff) {
-		tape->capabilities.ctl /= 2;
-		tape->data_buffer_size = tape->capabilities.ctl * tape->tape_block_size;
-	}
-	allocation_length=tape->data_buffer_size;
-	if (tape->data_buffer_size % IDETAPE_ALLOCATION_BLOCK)
-		allocation_length+=IDETAPE_ALLOCATION_BLOCK;
-	
-#if IDETAPE_MINIMIZE_IDLE_MEMORY_USAGE
-	tape->data_buffer=tape->merge_buffer=NULL;
-#else
-	tape->data_buffer=kmalloc (allocation_length,GFP_KERNEL);
-	tape->merge_buffer=kmalloc (allocation_length,GFP_KERNEL);
-	if (tape->data_buffer == NULL || tape->merge_buffer == NULL) {
-		printk ("ide-tape: FATAL - Can not allocate 2 buffers of %d bytes each\n",allocation_length);
-		printk ("ide-tape: Aborting character device installation\n");
-		idetape_drive_already_found=0;
-		unregister_chrdev (idetape_chrdev.major,idetape_chrdev.name);
-		return;
-	}
-#endif /* IDETAPE_MINIMIZE_IDLE_MEMORY_USAGE */
-
-	tape->merge_buffer_size=tape->merge_buffer_offset=0;
-	
-#if IDETAPE_ANTICIPATE_READ_WRITE_DSC
-
-	/*
-	 *	Cleverly select the DSC read/write polling frequency, based
-	 *	on the tape's speed, its recommended transfer unit, its
-	 *	internal buffer size and our operation mode.
-	 *
-	 *	In the pipelined operation mode we aim for "catching" the
-	 *	tape when its internal buffer is about 50% full. This will
-	 *	dramatically reduce our polling frequency and will also
-	 *	leave enough time for the ongoing request of the other device
-	 *	to complete before the buffer is completely empty. We will
-	 *	then completely refill the buffer with requests from our
-	 *	internal pipeline.
-	 *
-	 *	When operating in the non-pipelined operation mode, we
-	 *	can't allow ourself this luxury. Instead, we will try to take
-	 *	full advantage of the internal tape buffer by waiting only
-	 *	for one request to complete. This will increase our load
-	 *	on linux but will usually still fail to keep the tape
-	 *	constantly streaming.
-	 */
-
-	/*
-	 *	We will ignore the above algorithm for now, as it can have
-	 *	a bad effect on interactive response under some conditions.
-	 *	The following attempts to find a balance between good latency
-	 *	and good system throughput. It will be nice to have all this
-	 *	configurable in run time at some point.
-	 */
-	t1 = (tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000);
-	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125);
-	tn = (IDETAPE_FIFO_THRESHOLD * tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000);
-
-	if (tape->max_number_of_stages) {
-		if (drive->using_dma)
-			tape->best_dsc_rw_frequency = tmid;
-		else {
-			if (hwif->drives[drive->select.b.unit ^ 1].present || hwif->next != hwif)
-				tape->best_dsc_rw_frequency = IDETAPE_MIN ((tn + tmid) / 2, tmid);
-			else
-				tape->best_dsc_rw_frequency = IDETAPE_MIN (tn, tmid);
-		}
-	} else
-		tape->best_dsc_rw_frequency = t1;
-
-	/*
-	 *	Ensure that the number we got makes sense.
-	 */
-
-	if (tape->best_dsc_rw_frequency > IDETAPE_DSC_READ_WRITE_LOWEST_FREQUENCY) {
-		printk ("ide-tape: Although the recommended polling period is %lu jiffies, \n",tape->best_dsc_rw_frequency);
-		printk ("ide-tape: we will use %u jiffies\n",IDETAPE_DSC_READ_WRITE_LOWEST_FREQUENCY);
-		printk ("ide-tape: (It may well be that we are wrong here)\n");
-		tape->best_dsc_rw_frequency = IDETAPE_DSC_READ_WRITE_LOWEST_FREQUENCY;
-	}
-
-	if (tape->best_dsc_rw_frequency < IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY) {
-		printk ("ide-tape: Although the recommended polling period is %lu jiffies, \n",tape->best_dsc_rw_frequency);
-		printk ("ide-tape: we will use %u jiffies\n",IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY);
-		tape->best_dsc_rw_frequency = IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY;
-	}
-
-#else
-	tape->best_dsc_rw_frequency=IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY;
-#endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
-
-	printk (KERN_INFO "ide-tape: %s <-> %s, %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
-		drive->name, "ht0", tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->data_buffer_size,
-		tape->data_buffer_size / 1024, tape->max_number_of_stages * tape->data_buffer_size / 1024,
-		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
-	return;
-}
-
-/*
- *	idetape_get_mode_sense_results asks the tape about its various
- *	parameters. In particular, we will adjust our data transfer buffer
- *	size to the recommended value as returned by the tape.
- */
-
-void idetape_get_mode_sense_results (ide_drive_t *drive)
-
-{
-	int retval;
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_mode_parameter_header_t *header;
-	idetape_capabilities_page_t *capabilities;
-	idetape_packet_command_t pc;
-	
-	idetape_create_mode_sense_cmd (&pc,IDETAPE_CAPABILITIES_PAGE);
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
-	retval=idetape_queue_pc_tail (drive,&pc);
-
-	header=(idetape_mode_parameter_header_t *) pc.buffer;	
-	capabilities=(idetape_capabilities_page_t *) (pc.buffer+sizeof (idetape_mode_parameter_header_t));
-
-	capabilities->max_speed=idetape_swap_short (capabilities->max_speed);
-	capabilities->ctl=idetape_swap_short (capabilities->ctl);
-	capabilities->speed=idetape_swap_short (capabilities->speed);
-	capabilities->buffer_size=idetape_swap_short (capabilities->buffer_size);
-
-	tape->capabilities=*capabilities;		/* Save us a copy */
-	tape->tape_block_size=capabilities->blk512 ? 512:1024;
-
-	if (retval) {
-		printk ("ide-tape: Can't get tape parameters\n");
-		printk ("ide-tape: Assuming some default parameters\n");
-		tape->tape_block_size=512;
-		tape->capabilities.ctl=52;
-		tape->capabilities.speed=450;
-		tape->capabilities.buffer_size=6*52;
-		return;
-	}
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Dumping the results of the MODE SENSE packet command\n");
-	printk ("Mode Parameter Header:\n");
-	printk ("Mode Data Length - %d\n",header->mode_data_length);
-	printk ("Medium Type - %d\n",header->medium_type);
-	printk ("Device Specific Parameter - %d\n",header->dsp);
-	printk ("Block Descriptor Length - %d\n",header->bdl);
-	
-	printk ("Capabilities and Mechanical Status Page:\n");
-	printk ("Page code - %d\n",capabilities->page_code);
-	printk ("Page length - %d\n",capabilities->page_length);
-	printk ("Read only - %s\n",capabilities->ro ? "Yes":"No");
-	printk ("Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-	printk ("Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-	printk ("Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-	printk ("Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-	printk ("The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-	printk ("The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-	printk ("Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-	printk ("Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-	printk ("Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-	printk ("Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-	printk ("Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-	printk ("Restricted byte count for PIO transfers - %s\n",capabilities->slowb ? "Yes":"No");
-	printk ("Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-	printk ("Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-	printk ("Current speed in KBps - %d\n",capabilities->speed);	
-	printk ("Buffer size - %d\n",capabilities->buffer_size*512);
-#endif /* IDETAPE_DEBUG_LOG */
-}
-
-/*
- *	Packet Command Interface
- *
- *	The current Packet Command is available in tape->pc, and will not
- *	change until we finish handling it. Each packet command is associated
- *	with a callback function that will be called when the command is
- *	finished.
- *
- *	The handling will be done in three stages:
- *
- *	1.	idetape_issue_packet_command will send the packet command to the
- *		drive, and will set the interrupt handler to idetape_pc_intr.
- *
- *	2.	On each interrupt, idetape_pc_intr will be called. This step
- *		will be repeated until the device signals us that no more
- *		interrupts will be issued.
- *
- *	3.	ATAPI Tape media access commands have immediate status with a
- *		delayed process. In case of a successful initiation of a
- *		media access packet command, the DSC bit will be set when the
- *		actual execution of the command is finished. 
- *		Since the tape drive will not issue an interrupt, we have to
- *		poll for this event. In this case, we define the request as
- *		"low priority request" by setting rq_status to
- *		IDETAPE_RQ_POSTPONED, 	set a timer to poll for DSC and exit
- *		the driver.
- *
- *		ide.c will then give higher priority to requests which
- *		originate from the other device, until will change rq_status
- *		to RQ_ACTIVE.
- *
- *	4.	When the packet command is finished, it will be checked for errors.
- *
- *	5.	In case an error was found, we queue a request sense packet command
- *		in front of the request queue and retry the operation up to
- *		IDETAPE_MAX_PC_RETRIES times.
- *
- *	6.	In case no error was found, or we decided to give up and not
- *		to retry again, the callback function will be called and then
- *		we will handle the next request.
- *
- */
-
-void idetape_issue_packet_command  (ide_drive_t *drive,idetape_packet_command_t *pc,ide_handler_t *handler)
-
-{
-	idetape_tape_t *tape;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
-	int dma_ok=0;
-
-	tape=&(drive->tape);
-	        
-#if IDETAPE_DEBUG_BUGS
-	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		printk ("ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
-	}
-#endif /* IDETAPE_DEBUG_BUGS */
-
-	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
-		tape->failed_pc=pc;
-	tape->pc=pc;							/* Set the current packet command */
-
-	if (pc->retries > IDETAPE_MAX_PC_RETRIES || pc->abort) {
-
-		/*
-		 *	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).
-		 */
-
-		if (!pc->abort) {
-			printk ("ide-tape: %s: I/O error, ",drive->name);
-			printk ("pc = %x, key = %x, asc = %x, ascq = %x\n",pc->c[0],tape->sense_key,tape->asc,tape->ascq);
-#if IDETAPE_DEBUG_LOG
-			printk ("ide-tape: Maximum retries reached - Giving up\n");
-#endif /* IDETAPE_DEBUG_LOG */
-			pc->error=1;					/* Giving up */
-		}
-		tape->failed_pc=NULL;
-#if IDETAPE_DEBUG_BUGS
-		if (pc->callback==NULL)
-			printk ("ide-tape: ide-tape bug - Callback function not set !\n");
-		else
-#endif /* IDETAPE_DEBUG_BUGS */
-			(*pc->callback)(drive);
-		return;
-	}
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Retry number - %d\n",pc->retries);
-#endif /* IDETAPE_DEBUG_LOG */
-
-	pc->retries++;
-
-/*
- *	We no longer call ide_wait_stat to wait for the drive to be ready,
- *	as ide.c already does this for us in do_request.
- */
- 
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;	
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
-
-#ifdef CONFIG_BLK_DEV_TRITON
-	if (pc->dma_error) {
-		printk ("ide-tape: DMA disabled, reverting to PIO\n");
-		drive->using_dma=0;
-		pc->dma_error=0;
-	}
-	if (pc->request_transfer && pc->dma_recommended && drive->using_dma) {
-		dma_ok=!(HWIF(drive)->dmaproc(pc->writing ? ide_dma_write : ide_dma_read, drive));
-	}		
-#endif /* CONFIG_BLK_DEV_TRITON */
-
-	OUT_BYTE (drive->ctl,IDETAPE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDETAPE_FEATURES_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDETAPE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDETAPE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDETAPE_DRIVESEL_REG);
-	
-	ide_set_handler (drive,handler,WAIT_CMD);			/* Set the interrupt routine */
-	OUT_BYTE (WIN_PACKETCMD,IDETAPE_ATACOMMAND_REG);		/* Issue the packet command */
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { 	/* Wait for DRQ to be ready - Assuming Accelerated DRQ */	
-		/*
-		 *	We currently only support tape drives which report
-		 *	accelerated DRQ assertion. For this case, specs
-		 *	allow up to 50us. We really shouldn't get here.
-		 *
-		 *	??? Still needs to think what to do if we reach
-		 *	here anyway.
-		 */
-		 
-		printk ("ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
-	}
-	
-	ireason.all=IN_BYTE (IDETAPE_IREASON_REG);
-	if (!ireason.b.cod || ireason.b.io) {
-		printk ("ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;		
-	}
-		
-	ide_output_data (drive,pc->c,12/4);			/* Send the actual packet */
-#ifdef CONFIG_BLK_DEV_TRITON
-	if ((pc->dma_in_progress=dma_ok)) {			/* Begin DMA, if necessary */
-		pc->dma_error=0;
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-#endif /* CONFIG_BLK_DEV_TRITON */
-}
-
-/*
- *	idetape_pc_intr is the usual interrupt handler which will be called
- *	during a packet command. We will transfer some of the data (as
- *	requested by the drive) and will re-point interrupt handler to us.
- *	When data transfer is finished, we will act according to the
- *	algorithm described before idetape_issue_packet_command.
+ *	idetape_queue_pc_head generates a new packet command request in front
+ *	of the request queue, before the current request, so that it will be
+ *	processed immediately, on the next pass through the driver.
  *
- */
- 
-
-void idetape_pc_intr (ide_drive_t *drive)
-
-{
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_status_reg_t status;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
-	idetape_packet_command_t *pc=tape->pc;
-	unsigned long temp;
-
-#ifdef CONFIG_BLK_DEV_TRITON
-	if (pc->dma_in_progress) {
-		if ((pc->dma_error=HWIF(drive)->dmaproc(ide_dma_status_bad, drive)))
-			/*
-			 *	We will currently correct the following in
-			 *	idetape_analyze_error.
-			 */
-			pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive);
-		else
-			pc->actually_transferred=pc->request_transfer;
-		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));	/* End DMA */
-#if IDETAPE_DEBUG_LOG
-		printk ("ide-tape: DMA finished\n");
-#endif /* IDETAPE_DEBUG_LOG */
-	}
-#endif /* CONFIG_BLK_DEV_TRITON */
-
-	status.all=IN_BYTE (IDETAPE_STATUS_REG);		/* Clear the interrupt */
-
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Reached idetape_pc_intr interrupt handler\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-
-	if (!status.b.drq) {					/* No more interrupts */
-#if IDETAPE_DEBUG_LOG
-		printk ("Packet command completed\n");
-		printk ("Total bytes transferred: %lu\n",pc->actually_transferred);
-#endif /* IDETAPE_DEBUG_LOG */
-		pc->dma_in_progress=0;
-						
-		sti ();
-
-		if (status.b.check || pc->dma_error) {			/* Error detected */
-#if IDETAPE_DEBUG_LOG
-	/*
-	 *	Without debugging, we only log an error if we decided to
-	 *	give up retrying.
-	 */
-			printk ("ide-tape: %s: I/O error, ",drive->name);
-#endif /* IDETAPE_DEBUG_LOG */
-			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-				printk ("ide-tape: I/O error in request sense command\n");
-				ide_do_reset (drive);
-				return;
-			}			
-						
-			idetape_retry_pc (drive);			/* Retry operation */
-			return;
-		}
-		pc->error=0;
-		if (pc->wait_for_dsc && !status.b.dsc) {				/* Media access command */
-			tape->dsc_polling_frequency=IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY;
-			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
-			return;
-		}
-		if (tape->failed_pc == pc)
-			tape->failed_pc=NULL;
-#if IDETAPE_DEBUG_BUGS
-		if (pc->callback==NULL)			
-			printk ("ide-tape: ide-tape bug - Callback function not set !\n");
-		else
-#endif /* IDETAPE_DEBUG_BUGS */
-			(*pc->callback)(drive);			/* Command finished - Call the callback function */
-		return;
-	}
-#ifdef CONFIG_BLK_DEV_TRITON
-	if (pc->dma_in_progress) {
-		pc->dma_in_progress=0;
-		printk ("ide-tape: The tape wants to issue more interrupts in DMA mode\n");
-		printk ("ide-tape: DMA disabled, reverting to PIO\n");
-		drive->using_dma=0;
-		ide_do_reset (drive);
-		return;
-	}
-#endif /* CONFIG_BLK_DEV_TRITON */
-	bcount.b.high=IN_BYTE (IDETAPE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low=IN_BYTE (IDETAPE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all=IN_BYTE (IDETAPE_IREASON_REG);			/* Read the interrupt reason register */
-
-	if (ireason.b.cod) {
-		printk ("ide-tape: CoD != 0 in idetape_pc_intr\n");
-		ide_do_reset (drive);
-		return;
-	}
-	if (ireason.b.io != !(pc->writing)) {			/* Hopefully, we will never get here */
-		printk ("ide-tape: We wanted to %s, ",pc->writing ? "Write":"Read");
-		printk ("but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		ide_do_reset (drive);
-		return;
-	}
-	
-	if (!pc->writing) {					/* Reading - Check that we have enough space */
-		temp=(unsigned long) pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
-			if (temp > pc->buffer_size) {
-				printk ("ide-tape: The tape wants to send us more data than requested - discarding data\n");
-				idetape_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);
-				return;
-			}
-#if IDETAPE_DEBUG_LOG
-			printk ("ide-tape: The tape wants to send us more data than requested - allowing transfer\n");
-#endif /* IDETAPE_DEBUG_LOG */
-		}
-	}
-#if IDETAPE_DEBUG_BUGS	
-	if (bcount.all && !pc->buffer) {	
-		printk ("ide-tape: ide-tape.c bug - Buffer not set in idetape_pc_intr. Discarding data.\n");
-		
-		if (!pc->writing) {
-			printk ("ide-tape: Discarding data\n");
-			idetape_discard_data (drive,bcount.all);
-			ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);
-			return;
-		}
-		else {	/* ??? */
-		}
-	}
-#endif /* IDETAPE_DEBUG_BUGS */
-	if (pc->writing)
-		idetape_output_data (drive,pc->current_position,bcount.all);	/* Write the current buffer */
-	else
-		idetape_input_data (drive,pc->current_position,bcount.all);	/* Read the current buffer */
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: %s %d bytes\n",pc->writing ? "Wrote":"Received",bcount.all);
-#endif /* IDETAPE_DEBUG_LOG */
-	pc->actually_transferred+=bcount.all;					/* Update the current position */
-	pc->current_position+=bcount.all;
-
-	ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);		/* And set the interrupt handler again */
-}
-
-/*
- *	idetape_postpone_request postpones the current request so that
- *	ide.c will be able to service requests from another device on
- *	the same hwgroup while we are polling for DSC.
- */
-
-void idetape_postpone_request (ide_drive_t *drive)
-
-{
-	idetape_tape_t *tape=&(drive->tape);
-	struct request *rq;
-	idetape_status_reg_t status;
-	
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_postpone_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
-	if (tape->postponed_rq != NULL)
-		printk ("ide-tape.c bug - postponed_rq not NULL in idetape_postpone_request\n");
-#endif /* IDETAPE_DEBUG_BUGS */
-
-	tape->dsc_timer.expires=jiffies + tape->dsc_polling_frequency;	/* Set timer to poll for */
-	tape->dsc_timeout=jiffies+IDETAPE_DSC_TIMEOUT;			/* actual completion */
-	tape->dsc_timer.data=(unsigned long) drive;
-	tape->dsc_timer.function=&idetape_poll_for_dsc;
-	init_timer (&(tape->dsc_timer));
-
-	/*
-	 * Remove current request from the request queue:
-	 */
-
-	tape->postponed_rq = rq = HWGROUP(drive)->rq;
-	rq->rq_status = IDETAPE_RQ_POSTPONED;	
-	blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next;
-	HWGROUP(drive)->rq = NULL;
-
-	/*
-	 *	Check the status again - Maybe we can save one polling period.
-	 */
-	 
-	status.all=IN_BYTE (IDETAPE_STATUS_REG);
-	tape->last_status=status.all;
-	tape->request_status=1;	
-	
-	tape->dsc_polling_start=jiffies;
-	add_timer(&(tape->dsc_timer));		/* Activate the polling timer */
-}
-
-/*
- *	idetape_poll_for_dsc_direct is called from idetape_poll_for_dsc
- *	to handle the case in which we can safely communicate with the tape
- *	(since no other request for this hwgroup is active).
- */
- 
-void idetape_poll_for_dsc_direct (unsigned long data)
-
-{
-	ide_drive_t *drive=(ide_drive_t *) data;
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_status_reg_t status;
-
-#if IDETAPE_DEBUG_LOG
-	printk ("%s: idetape_poll_for_dsc_direct called\n",drive->name);
-#endif /* IDETAPE_DEBUG_LOG */	
-
-	OUT_BYTE(drive->select.all,IDE_SELECT_REG);
-	status.all=IN_BYTE (IDETAPE_STATUS_REG);
-	
-	if (status.b.dsc) {					/* DSC received */
-		tape->dsc_received=1;
-		del_timer (&(tape->dsc_timer));			/* Stop polling and put back the postponed */
-		idetape_put_back_postponed_request (drive);	/* request in the request queue */
-		return;
-	}
-
-	if (jiffies > tape->dsc_timeout) 	{ /* Timeout */
-		tape->dsc_received=0;
-		del_timer (&(tape->dsc_timer));
-		/* ??? */
-		idetape_put_back_postponed_request (drive);
-		return;
-	}
-
-	/* Poll again */
-	
-	if (jiffies - tape->dsc_polling_start > IDETAPE_FAST_SLOW_THRESHOLD)
-		tape->dsc_timer.expires = jiffies + IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY;
-	else
-		tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency;
-	add_timer(&(tape->dsc_timer));
-	return;
-}
-
-/*
- *	idetape_poll_for_dsc gets invoked by a timer (which was set
- *	by idetape_postpone_request) to poll for the DSC bit
- *	in the status register.
+ *	idetape_queue_pc_head is called from the request handling part of
+ *	the driver (the "bottom" part). Safe storage for the request should
+ *	be allocated with idetape_next_pc_storage and idetape_next_rq_storage
+ *	before calling idetape_queue_pc_head.
  *
- *	We take care not to perform any tape access if the driver is
- *	accessing the other device. We will instead ask ide.c to sample
- *	the tape status register on our behalf in the next call to do_request,
- *	at the point in which the other device is idle, or assume that
- *	DSC was received even though we won't verify it (but when we assume
- *	that, it will usually have a solid basis).
+ *	Memory for those requests is pre-allocated at initialization time, and
+ *	is limited to IDETAPE_PC_STACK requests. We assume that we have enough
+ *	space for the maximum possible number of inter-dependent packet commands.
  *
- *	The use of cli () below is a must, as we inspect and change
- *	the device request list while another request is active.
+ *	The higher level of the driver - The ioctl handler and the character
+ *	device handling functions should queue request to the lower level part
+ *	and wait for their completion using idetape_queue_pc_tail or
+ *	idetape_queue_rw_tail.
  */
- 
-void idetape_poll_for_dsc (unsigned long data)
-
+static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
 {
-	ide_drive_t *drive=(ide_drive_t *) data;
 	unsigned int major = HWIF(drive)->major;
-	idetape_tape_t *tape=&(drive->tape);
 	struct blk_dev_struct *bdev = &blk_dev[major];
-	struct request *next_rq;
-	unsigned long flags;
-	idetape_status_reg_t status;
-
-#if IDETAPE_DEBUG_LOG
-	printk ("%s: idetape_poll_for_dsc called\n",drive->name);
-#endif /* IDETAPE_DEBUG_LOG */	
-
-	save_flags (flags);cli ();
-
-	/*
-	 *	Check if the other device is idle. If there are no requests,
-	 *	we can safely access the tape.
-	 */
-
-	if (HWGROUP (drive)->rq == NULL) {
-		sti ();
-		idetape_poll_for_dsc_direct (data);
-		return;
-	}
-
-	/*
-	 *	If DSC was received, re-insert our postponed request into
-	 *	the request queue (using ide_next).
-	 */
-
-	status.all=tape->last_status;
-
-	if (status.b.dsc) {					/* DSC received */
-		tape->dsc_received=1;
-		idetape_put_back_postponed_request (drive);
-		del_timer (&(tape->dsc_timer));
-		restore_flags (flags);
-		return;
-	}
-
-	/*
-	 *	At this point, DSC may have been received, but we can't
-	 *	check it. We now have two options:
-	 *
-	 *		1.	The "simple" method - We can continue polling
-	 *			until we know the value of DSC.
-	 *
-	 *	but we also have a more clever option :-)
-	 *
-	 *		2.	We can sometimes more or less anticipate in
-	 *			advance how much time it will take for
-	 *			the tape to perform the request. This is the
-	 *			place to take advantage of this !
-	 *
-	 *			We can assume that DSC was received, put
-	 *			back our request, and hope that we will have
-	 *			a "cache hit". This will only work when
-	 *			we haven't initiated the packet command yet,
-	 *			but this is the common read/write case. As
-	 *			for the slower media access commands, fallback
-	 *			to method 1 above.
-	 *
-	 *	When using method 2, we can also take advantage of the
-	 *	knowledge of the tape's internal buffer size - We can
-	 *	precalculate the time it will take for the tape to complete
-	 *	servicing not only one request, but rather, say, 50% of its
-	 *	internal buffer. The polling period will then be much larger,
-	 *	decreasing our load on Linux, and we will also call
-	 *	idetape_postpone_request less often, as there will usually
-	 *	be more room in the internal tape buffer while we are in
-	 *	idetape_do_request.
-	 *
-	 *	For this method to work well, the ongoing request of the
-	 *	other device should be serviced by the time the tape is
-	 *	still working on its remaining 50% internal buffer. This
-	 *	will usually happen when the other device is much faster
-	 *	than the tape.
-	 */
-
-#if IDETAPE_ANTICIPATE_READ_WRITE_DSC
-
-	/*
-	 *	Method 2.
-	 *
-	 *	There is a high chance that DSC was received, even though
-	 *	we couldn't verify it. Let's hope that it's a "cache hit"
-	 *	rather than a "cache miss". Someday I will probably add a
-	 *	feedback loop around the number of "cache hits" which will
-	 *	fine-tune the polling period.
-	 */
-	 
-	if (tape->postponed_rq->cmd != IDETAPE_PACKET_COMMAND_REQUEST_TYPE1) {
-
-		/*
-		 *	We can use this method only when the packet command
-		 *	was still not initiated.
-		 */
-		 
-		idetape_put_back_postponed_request (drive);
-		del_timer (&(tape->dsc_timer));
-		restore_flags (flags);
-		return;
-	}
-#endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
-
-	/*
-	 *	Fallback to method 1.
-	 */
-
-	next_rq=bdev->current_request;
-	if (next_rq == HWGROUP (drive)->rq)
-		next_rq=next_rq->next;
-
-	if (next_rq == NULL) {
-
-		/*
-		 *	There will not be another request after the currently
-		 *	ongoing request, so ide.c won't be able to sample
-		 *	the status register on our behalf in do_request.
-		 *
-		 *	In case we are waiting for DSC before the packet
-		 *	command was initiated, we will put back our postponed
-		 *	request and have another look at the status register
-		 *	in idetape_do_request, as done in method 2 above.
-		 *
-		 *	In case we already initiated the command, we can't
-		 *	put it back, but it is anyway a slow media access
-		 *	command. We will just give up and poll again until
-		 *	we are lucky.
-		 */
-
-		if (tape->postponed_rq->cmd == IDETAPE_PACKET_COMMAND_REQUEST_TYPE1) {
-
-			/*
-			 *	Media access command - Poll again.
-			 *
-			 *	We set tape->request_status to 1, just in case
-			 *	other requests are added while we are waiting.
-			 */
-			 
-			tape->request_status=1;
-			restore_flags (flags);
-			tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency;
-			add_timer(&(tape->dsc_timer));
-			return;
-		}
-		
-		/*
-		 *	The packet command hasn't been sent to the tape yet -
-		 *	We can safely put back the request and have another
-		 *	look at the status register in idetape_do_request.
-		 */
-
-		idetape_put_back_postponed_request (drive);
-		del_timer (&(tape->dsc_timer));
-		restore_flags (flags);
-		return;
-	}
-
-	/*
-	 *	There will be another request after the current request.
-	 *
-	 *	Request ide.c to sample for us the tape's status register
-	 *	before the next request.
-	 */
-
-	tape->request_status=1;
-	restore_flags (flags);
 
-	if (jiffies > tape->dsc_timeout) 	{ 		/* Timeout */
-		tape->dsc_received=0;
-		/* ??? */
-		idetape_put_back_postponed_request (drive);
-		del_timer (&(tape->dsc_timer));
-		restore_flags (flags);
-		return;
-	}
+	bdev->current_request=HWGROUP (drive)->rq;		/* Since we may have taken it out */
 
-	/* Poll again */
-	
-	if (jiffies - tape->dsc_polling_start > IDETAPE_FAST_SLOW_THRESHOLD)
-		tape->dsc_timer.expires = jiffies + IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY;
-	else
-		tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency;
-	add_timer(&(tape->dsc_timer));
-	return;
+	ide_init_drive_cmd (rq);
+	rq->buffer = (char *) pc;
+	rq->cmd = IDETAPE_PC_RQ;
+	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
 /*
- *	idetape_put_back_postponed_request gets called when we decided to
- *	stop polling for DSC and continue servicing our postponed request.
+ *	idetape_next_pc_storage returns a pointer to a place in which we can
+ *	safely store a packet command, even though we intend to leave the
+ *	driver. A storage space for a maximum of IDETAPE_PC_STACK packet
+ *	commands is allocated at initialization time.
  */
-
-void idetape_put_back_postponed_request (ide_drive_t *drive)
-
+static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
 {
-	idetape_tape_t *tape = &(drive->tape);
+	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Putting back postponed request\n");
+	printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
-	if (tape->postponed_rq == NULL) {
-		printk ("tape->postponed_rq is NULL in put_back_postponed_request\n");
-		return;
-	}
-#endif /* IDETAPE_DEBUG_BUGS */
-	(void) ide_do_drive_cmd (drive, tape->postponed_rq, ide_next);
-
-	/*
-	 * 	Note that the procedure done here is different than the method
-	 *	we are using in idetape_queue_pc_head - There we are putting
-	 *	request(s) before our currently called request.
-	 *
-	 *	Here, on the other hand, HWGROUP(drive)->rq is not our
-	 *	request but rather a request to another device. Therefore,
-	 *	we will let it finish and only then service our postponed
-	 *	request --> We don't touch HWGROUP(drive)->rq.
-	 */
+	if (tape->pc_stack_index==IDETAPE_PC_STACK)
+		tape->pc_stack_index=0;
+	return (&tape->pc_stack[tape->pc_stack_index++]);
 }
 
-void idetape_media_access_finished (ide_drive_t *drive)
-
+/*
+ *	idetape_next_rq_storage is used along with idetape_next_pc_storage.
+ *	Since we queue packet commands in the request queue, we need to
+ *	allocate a request, along with the allocation of a packet command.
+ */
+ 
+/**************************************************************
+ *                                                            *
+ *  This should get fixed to use kmalloc(GFP_ATOMIC, ..)      *
+ *  followed later on by kfree().   -ml                       *
+ *                                                            *
+ **************************************************************/
+ 
+static struct request *idetape_next_rq_storage (ide_drive_t *drive)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_status_reg_t status;
-	idetape_packet_command_t *pc;
-
-	pc=tape->pc;
-	
-	status.all=IN_BYTE (IDETAPE_STATUS_REG);
+	idetape_tape_t *tape = drive->driver_data;
 
-	if (tape->dsc_received) {
 #if IDETAPE_DEBUG_LOG
-		printk ("DSC received\n");
+	printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-		if (status.b.check) {					/* Error detected */
-			printk ("ide-tape: %s: I/O error, ",drive->name);
-			idetape_retry_pc (drive);			/* Retry operation */
-			return;
-		}
-		pc->error=0;
-		if (tape->failed_pc == pc)
-			tape->failed_pc=NULL;
-#if IDETAPE_DEBUG_BUGS
-		if (pc->callback==NULL)
-			printk ("ide-tape: ide-tape bug - Callback function not set !\n");
-		else
-#endif /* IDETAPE_DEBUG_BUGS */
-			(*pc->callback)(drive);
-
-		return;
-	}
-	else {
-		printk ("ide-tape: %s: DSC timeout.\n",drive->name);
-		/* ??? */
-		pc->error=1;
-		tape->failed_pc=NULL;
-#if IDETAPE_DEBUG_BUGS
-		if (pc->callback==NULL)
-			printk ("ide-tape: ide-tape bug - Callback function not set !\n");
-		else
-#endif /* IDETAPE_DEBUG_BUGS */
-			(*pc->callback)(drive);
-		return;
-	}
+	if (tape->rq_stack_index==IDETAPE_PC_STACK)
+		tape->rq_stack_index=0;
+	return (&tape->rq_stack[tape->rq_stack_index++]);
 }
 
-
 /*
- *	idetape_retry_pc is called when an error was detected during the
- *	last packet command. We queue a request sense packet command in
- *	the head of the request list.
+ *	Pipeline related functions
  */
- 
-void idetape_retry_pc (ide_drive_t *drive)
 
+static inline int idetape_pipeline_active (idetape_tape_t *tape)
 {
-	idetape_tape_t *tape = &drive->tape;
-	idetape_packet_command_t *pc;
-	struct request *new_rq;
-
-	idetape_error_reg_t error;
-	error.all=IN_BYTE (IDETAPE_ERROR_REG);
-	pc=idetape_next_pc_storage (drive);
-	new_rq=idetape_next_rq_storage (drive);
-	idetape_create_request_sense_cmd (pc); 
-	pc->buffer=pc->temp_buffer;
-	pc->buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc->current_position=pc->temp_buffer;
-	tape->reset_issued = 1;
-	idetape_queue_pc_head (drive,pc,new_rq);
+	return tape->active_data_request != NULL;
 }
 
 /*
- *	General packet command callback function.
+ *	idetape_kfree_stage calls kfree to completely free a stage, along with
+ *	its related buffers.
  */
- 
-void idetape_pc_callback (ide_drive_t *drive)
-
+static void __idetape_kfree_stage (idetape_stage_t *stage)
 {
-	idetape_tape_t *tape;
-	struct request *rq;
-	
-	tape=&(drive->tape);
-	rq=HWGROUP(drive)->rq;
-	
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Reached idetape_pc_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
-	if (!tape->pc->error) {
-#if IDETAPE_DEBUG_LOG
-		printk ("Request completed\n");
-#endif /* IDETAPE_DEBUG_LOG */
-		idetape_end_request (1,HWGROUP (drive));
-	}
-	else {
-		idetape_end_request (0,HWGROUP (drive));
+	struct buffer_head *prev_bh, *bh = stage->bh;
+	int size;
+
+	while (bh != NULL) {
+		if (bh->b_data != NULL) {
+			size = (int) bh->b_size;
+			while (size > 0) {
+				free_page ((unsigned long) bh->b_data);
+				size -= PAGE_SIZE;
+				bh->b_data += PAGE_SIZE;
+			}
+		}
+		prev_bh = bh;
+		bh = bh->b_reqnext;
+		kfree (prev_bh);
 	}
-	return;
+	kfree (stage);
 }
 
+static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
+{
+	if (tape->cache_stage == NULL)
+		tape->cache_stage = stage;
+	else
+		__idetape_kfree_stage (stage);
+}
 
-void idetape_read_callback (ide_drive_t *drive)
-
+/*
+ *	idetape_kmalloc_stage uses __get_free_page to allocate a pipeline
+ *	stage, along with all the necessary small buffers which together make
+ *	a buffer of size tape->stage_size (or a bit more). We attempt to
+ *	combine sequential pages as much as possible.
+ *
+ *	Returns a pointer to the new allocated stage, or NULL if we
+ *	can't (or don't want to) allocate a stage.
+ *
+ *	Pipeline stages are optional and are used to increase performance.
+ *	If we can't allocate them, we'll manage without them.
+ */
+static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	struct request *rq=HWGROUP(drive)->rq;
-	int blocks_read=tape->pc->actually_transferred/tape->tape_block_size;
+	idetape_stage_t *stage;
+	struct buffer_head *prev_bh, *bh;
+	int pages = tape->pages_per_stage;
+	char *b_data;
 
-#if IDETAPE_DEBUG_LOG	
-	printk ("ide-tape: Reached idetape_read_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+		return NULL;
+	stage->next = NULL;
 
-	tape->block_address+=blocks_read;
-	rq->current_nr_sectors-=blocks_read;	
+	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
+	if (bh == NULL)
+		goto abort;
+	bh->b_reqnext = NULL;
+	if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+		goto abort;
+	bh->b_size = PAGE_SIZE;
+	set_bit (BH_Lock, &bh->b_state);
 
-	if (!tape->pc->error)
-		idetape_end_request (1,HWGROUP (drive));
-	else {
-		rq->errors=tape->pc->error;
-		switch (rq->errors) {
-			case IDETAPE_RQ_ERROR_FILEMARK:
-			case IDETAPE_RQ_ERROR_EOD:
-				break;
+	while (--pages) {
+		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+			goto abort;
+		if (bh->b_data == b_data + PAGE_SIZE && virt_to_bus (bh->b_data) == virt_to_bus (b_data) + PAGE_SIZE) {
+			bh->b_size += PAGE_SIZE;
+			bh->b_data -= PAGE_SIZE;
+			continue;
 		}
-		idetape_end_request (0,HWGROUP (drive));
+		if (b_data == bh->b_data + bh->b_size && virt_to_bus (b_data) == virt_to_bus (bh->b_data) + bh->b_size) {
+			bh->b_size += PAGE_SIZE;
+			continue;
+		}
+		prev_bh = bh;
+		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
+			free_page ((unsigned long) b_data);
+			goto abort;
+		}
+		bh->b_reqnext = NULL;
+		bh->b_data = b_data;
+		bh->b_size = PAGE_SIZE;
+		set_bit (BH_Lock, &bh->b_state);
+		prev_bh->b_reqnext = bh;
 	}
-	return;
+	bh->b_size -= tape->excess_bh_size;
+	return stage;
+abort:
+	__idetape_kfree_stage (stage);
+	return NULL;
 }
 
-void idetape_write_callback (ide_drive_t *drive)
-
+static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	struct request *rq=HWGROUP(drive)->rq;
-	int blocks_written=tape->pc->actually_transferred/tape->tape_block_size;
-		
-#if IDETAPE_DEBUG_LOG	
-	printk ("ide-tape: Reached idetape_write_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+	idetape_stage_t *cache_stage = tape->cache_stage;
 
-	tape->block_address+=blocks_written;
-	rq->current_nr_sectors-=blocks_written;
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Reached idetape_kmalloc_stage\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
-	if (!tape->pc->error)
-		idetape_end_request (1,HWGROUP (drive));
-	else {
-		rq->errors=tape->pc->error;
-		idetape_end_request (0,HWGROUP (drive));
+	if (tape->nr_stages >= tape->max_stages)
+		return NULL;
+	if (cache_stage != NULL) {
+		tape->cache_stage = NULL;
+		return cache_stage;
 	}
-	return;
+	return __idetape_kmalloc_stage (tape);
 }
 
-void idetape_inquiry_callback (ide_drive_t *drive)
-
+static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
 {
-	idetape_tape_t *tape;
-	
-	tape=&(drive->tape);
-	
-	idetape_display_inquiry_result (tape->pc->buffer);
-	idetape_pc_callback (drive);
-	return;
-}
+	struct buffer_head *bh = tape->bh;
+	int count;
 
-/*
- *	idetape_input_data is called to read data from the tape's data
- *	register. We basically let ide_input_data do the job, but we also
- *	take care about the remaining bytes which can not be transferred
- *	in 32-bit data transfers.
- */
- 
-void idetape_input_data (ide_drive_t *drive,void *buffer, unsigned long bcount)
+	while (n) {
+#if IDETAPE_DEBUG_BUGS
+		if (bh == NULL) {
+			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+			return;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = IDETAPE_MIN (bh->b_size - bh->b_count, n);
+		copy_from_user (bh->b_data + bh->b_count, buf, count);
+		n -= count; bh->b_count += count; buf += count;
+		if (bh->b_count == bh->b_size) {
+			bh = bh->b_reqnext;
+			if (bh)
+				bh->b_count = 0;
+		}
+	}
+	tape->bh = bh;
+}
 
+static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
 {
-	unsigned long wcount;
-	
-	wcount=bcount >> 2;
-	bcount -= 4*wcount;
-	
-	if (wcount)
-		ide_input_data (drive,buffer,wcount);
-	
-	if (bcount) {
-		((byte *)buffer) += 4*wcount;
-		insb (IDETAPE_DATA_REG,buffer,bcount);
+	struct buffer_head *bh = tape->bh;
+	int count;
+
+	while (n) {
+#if IDETAPE_DEBUG_BUGS
+		if (bh == NULL) {
+			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+			return;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		count = IDETAPE_MIN (tape->b_count, n);
+		copy_to_user (buf, tape->b_data, count);
+		n -= count; tape->b_data += count; tape->b_count -= count; buf += count;
+		if (!tape->b_count) {
+			tape->bh = bh = bh->b_reqnext;
+			if (bh) {
+				tape->b_data = bh->b_data;
+				tape->b_count = bh->b_count;
+			}
+		}
 	}
 }
 
-/*
- *	idetape_output_data is used to write data to the tape.
- */
- 
-void idetape_output_data (ide_drive_t *drive,void *buffer, unsigned long bcount)
-
+static void idetape_init_merge_stage (idetape_tape_t *tape)
 {
-	unsigned long wcount;
-	
-	wcount=bcount >> 2;
-	bcount -= 4*wcount;
-	
-	if (wcount)
-		ide_output_data (drive,buffer,wcount);
+	struct buffer_head *bh = tape->merge_stage->bh;
 	
-	if (bcount) {
-		((byte *)buffer) += 4*wcount;
-		outsb (IDETAPE_DATA_REG,buffer,bcount);
+	tape->bh = bh;
+	if (tape->chrdev_direction == idetape_direction_write)
+		bh->b_count = 0;
+	else {
+		tape->b_data = bh->b_data;
+		tape->b_count = bh->b_count;
 	}
 }
 
+static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
+{
+	struct buffer_head *tmp;
+
+	tmp = stage->bh;
+	stage->bh = tape->merge_stage->bh;
+	tape->merge_stage->bh = tmp;
+	idetape_init_merge_stage (tape);
+}
+
 /*
- *	Too bad. The drive wants to send us data which we are not ready to accept.
- *	Just throw it away.
+ *	idetape_increase_max_pipeline_stages is a part of the feedback
+ *	loop which tries to find the optimum number of stages. In the
+ *	feedback loop, we are starting from a minimum maximum number of
+ *	stages, and if we sense that the pipeline is empty, we try to
+ *	increase it, until we reach the user compile time memory limit.
  */
- 
-void idetape_discard_data (ide_drive_t *drive, unsigned long bcount)
-
+static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
 {
-	unsigned long i;
+	idetape_tape_t *tape = drive->driver_data;
 	
-	for (i=0;i<bcount;i++)
-		IN_BYTE (IDETAPE_DATA_REG);
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Reached idetape_increase_max_pipeline_stages\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+	tape->max_stages = IDETAPE_MIN (tape->max_stages + IDETAPE_INCREASE_STAGES_RATE, IDETAPE_MAX_PIPELINE_STAGES);
 }
 
 /*
- *	Issue an INQUIRY packet command.
+ *	idetape_add_stage_tail adds a new stage at the end of the pipeline.
  */
- 
-void idetape_create_inquiry_cmd (idetape_packet_command_t *pc)
-
+static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
 {
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating INQUIRY packet command\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-	pc->request_transfer=36;
-	pc->callback=&idetape_inquiry_callback;
-	pc->writing=0;
+	idetape_tape_t *tape = drive->driver_data;
+	unsigned long flags;
 	
-	idetape_zero_packet_command (pc);
-	pc->c[0]=IDETAPE_INQUIRY_CMD;
-	pc->c[4]=255;
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Reached idetape_add_stage_tail\n");
+#endif /* IDETAPE_DEBUG_LOG */
+	save_flags (flags);
+	cli ();
+	stage->next=NULL;
+	if (tape->last_stage != NULL)
+		tape->last_stage->next=stage;
+	else
+		tape->first_stage=tape->next_stage=stage;
+	tape->last_stage=stage;
+	if (tape->next_stage == NULL)
+		tape->next_stage=tape->last_stage;
+	tape->nr_stages++;
+	tape->nr_pending_stages++;
+	restore_flags (flags);
 }
 
 /*
- *	Format the INQUIRY command results.
+ *	idetape_remove_stage_head removes tape->first_stage from the pipeline.
+ *	The caller should avoid race conditions.
  */
- 
-void idetape_display_inquiry_result (byte *buffer)
-
+static void idetape_remove_stage_head (ide_drive_t *drive)
 {
-	idetape_inquiry_result_t *result;
-
-	result=(idetape_inquiry_result_t *) buffer;
-	ide_fixstring (result->vendor_id,8,0);
-	ide_fixstring (result->product_id,16,0);
-	ide_fixstring (result->revision_level,4,0);
-
-	if (result->response_format != 2) {
-		printk ("The INQUIRY Data Format is unknown to us !\n");
-		printk ("Assuming QIC-157C format.\n");
-	}
-
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage;
+	
 #if IDETAPE_DEBUG_LOG
-	printk ("Dumping INQUIRY command results:\n");
-	printk ("Response Data Format: %d - ",result->response_format);
-	switch (result->response_format) {
-		case 2:
-			printk ("As specified in QIC-157 Revision C\n");
-			break;
-		default:
-			printk ("Unknown\n");
-			break;
+	printk (KERN_INFO "Reached idetape_remove_stage_head\n");
+#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+	if (tape->first_stage == NULL) {
+		printk (KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+		return;		
 	}
-	
-	printk ("Device Type: %x - ",result->device_type);	
-	switch (result->device_type) {
-		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");
+	if (tape->active_stage == tape->first_stage) {
+		printk (KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+		return;
 	}
-	
-	printk ("Removable Medium: %s",result->rmb ? "Yes\n":"No\n");
-
-	printk ("ANSI Version: %d - ",result->ansi_version);
-	switch (result->ansi_version) {
-		case 2:
-			printk ("QIC-157 Revision C\n");
-			break;
-		default:
-			printk ("Unknown\n");
-			break;
+#endif /* IDETAPE_DEBUG_BUGS */
+	stage=tape->first_stage;
+	tape->first_stage=stage->next;
+	idetape_kfree_stage (tape, stage);
+	tape->nr_stages--;
+	if (tape->first_stage == NULL) {
+		tape->last_stage=NULL;
+#if IDETAPE_DEBUG_BUGS
+		if (tape->next_stage != NULL)
+			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+		if (tape->nr_stages)
+			printk (KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+#endif /* IDETAPE_DEBUG_BUGS */
 	}
+}
 
-	printk ("ECMA Version: ");
-	if (result->ecma_version)
-		printk ("%d\n",result->ecma_version);
-	else
-		printk ("Not supported\n");
-
-	printk ("ISO Version: ");
-	if (result->iso_version)
-		printk ("%d\n",result->iso_version);
-	else
-		printk ("Not supported\n");
+/*
+ *	idetape_active_next_stage will declare the next stage as "active".
+ */
+static void idetape_active_next_stage (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage=tape->next_stage;
+	struct request *rq = &stage->rq;
 
-	printk ("Additional Length: %d\n",result->additional_length);
-	printk ("Vendor Identification: %s\n",result->vendor_id);
-	printk ("Product Identification: %s\n",result->product_id);
-	printk ("Product Revision Level: %s\n",result->revision_level);
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Reached idetape_active_next_stage\n");
 #endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+	if (stage == NULL) {
+		printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+		return;
+	}
+#endif /* IDETAPE_DEBUG_BUGS */	
 
-	if (result->device_type != 1)
-		printk ("Device type is not set to tape\n");
+	rq->buffer = NULL;
+	rq->bh = stage->bh;
+	tape->active_data_request=rq;
+	tape->active_stage=stage;
+	tape->next_stage=stage->next;
+}
 
-	if (!result->rmb)
-		printk ("The removable flag is not set\n");
+/*
+ *	idetape_insert_pipeline_into_queue is used to start servicing the
+ *	pipeline stages, starting from tape->next_stage.
+ */
+static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
 
-	if (result->ansi_version != 2) {
-		printk ("The Ansi Version is unknown to us !\n");
-		printk ("Assuming compliance with QIC-157C specification.\n");
+	if (tape->next_stage == NULL)
+		return;
+	if (!idetape_pipeline_active (tape)) {
+		idetape_active_next_stage (drive);
+		(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
 	}
 }
 
-void idetape_create_request_sense_cmd (idetape_packet_command_t *pc)
-
+static void idetape_abort_pipeline (ide_drive_t *drive)
 {
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating REQUEST SENSE packet command\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-	pc->request_transfer=18;
-	pc->callback=&idetape_request_sense_callback;
-	pc->writing=0;
-	
-	idetape_zero_packet_command (pc);	
-	pc->c[0]=IDETAPE_REQUEST_SENSE_CMD;
-	pc->c[4]=255;
-}
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage = tape->next_stage;
 
-void idetape_request_sense_callback (ide_drive_t *drive)
+	while (stage) {
+		stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
+		stage = stage->next;
+	}
+}
 
+/*
+ *	idetape_end_request is used to finish servicing a request, and to
+ *	insert a pending pipeline request into the main device queue.
+ */
+static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
 {
-	idetape_tape_t *tape=&(drive->tape);
+	ide_drive_t *drive = hwgroup->drive;
+	struct request *rq = hwgroup->rq;
+	idetape_tape_t *tape = drive->driver_data;
+	unsigned int major = HWIF(drive)->major;
+	struct blk_dev_struct *bdev = &blk_dev[major];
+	int error;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Reached idetape_request_sense_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
-	if (!tape->pc->error) {
-#if IDETAPE_DEBUG_LOG
-		printk ("Request completed\n");
+	printk (KERN_INFO "Reached idetape_end_request\n");
 #endif /* IDETAPE_DEBUG_LOG */
-		idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request (1,HWGROUP (drive));
-	}
-	else {
-		printk ("Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request (0,HWGROUP (drive));
+
+	bdev->current_request=rq;			/* Since we may have taken it out */
+
+	switch (uptodate) {
+		case 0:	error = IDETAPE_ERROR_GENERAL; break;
+		case 1: error = 0; break;
+		default: error = uptodate;
+	}
+	rq->errors = error;
+	if (error)
+		tape->failed_pc = NULL;
+
+	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+		tape->active_stage = NULL;
+		tape->active_data_request = NULL;
+		tape->nr_pending_stages--;
+		if (rq->cmd == IDETAPE_WRITE_RQ) {
+			if (error) {
+				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				if (error == IDETAPE_ERROR_EOD)
+					idetape_abort_pipeline (drive);
+			}
+			idetape_remove_stage_head (drive);
+		}
+		if (tape->next_stage != NULL) {
+			idetape_active_next_stage (drive);
+
+			/*
+			 *	Insert the next request into the request queue.
+			 *	The choice of using ide_next or ide_end is now left to the user.
+			 */
+#if IDETAPE_LOW_TAPE_PRIORITY
+			(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+#else
+			(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_next);
+#endif /* IDETAPE_LOW_TAPE_PRIORITY */
+		} else if (!error)
+			idetape_increase_max_pipeline_stages (drive);
 	}
-	return;
+	ide_end_drive_cmd (drive, 0, 0);
 }
 
 /*
@@ -2449,515 +1659,603 @@
  *	to analyze the request sense. We currently do not utilize this
  *	information.
  */
- 
-void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result)
-
+static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_packet_command_t *pc=tape->failed_pc;
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t *pc = tape->failed_pc;
 		
-	tape->sense_key=result->sense_key;
-	tape->asc=result->asc;
-	tape->ascq=result->ascq;
-	
-#if IDETAPE_DEBUG_LOG	
+	tape->sense_key = result->sense_key; tape->asc = result->asc; tape->ascq = result->ascq;
+#if IDETAPE_DEBUG_LOG
 	/*
 	 *	Without debugging, we only log an error if we decided to
 	 *	give up retrying.
 	 */
-	printk ("ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq);
+	printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (pc->c[0] == IDETAPE_READ_CMD) {
-		if (result->filemark) {
-			pc->error=IDETAPE_RQ_ERROR_FILEMARK;
-			pc->abort=1;
-		}
-	}
-
-	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
-		if (result->sense_key == 8) {
-			pc->error=IDETAPE_RQ_ERROR_EOD;
-			pc->abort=1;
-		}
-	}
-
-#if 1
 #ifdef CONFIG_BLK_DEV_TRITON
 
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
-
-	if (pc->dma_error && pc->abort) {
-		unsigned long *long_ptr=(unsigned long *) &(result->information1);
-		pc->actually_transferred=pc->request_transfer-tape->tape_block_size*idetape_swap_long (*long_ptr);
-	}		
+	if (test_bit (PC_DMA_ERROR, &pc->flags)) {
+		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information));
+		idetape_update_buffers (pc);
+	}
 #endif /* CONFIG_BLK_DEV_TRITON */
-#endif
-}
-
-void idetape_create_test_unit_ready_cmd (idetape_packet_command_t *pc)
-
-{
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating TEST UNIT READY packet command\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-	
-	idetape_zero_packet_command (pc);	
-	pc->c[0]=IDETAPE_TEST_UNIT_READY_CMD;
+	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
+		pc->error = IDETAPE_ERROR_FILEMARK;
+		set_bit (PC_ABORT, &pc->flags);
+	}
+	if (pc->c[0] == IDETAPE_WRITE_CMD) {
+		if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) {
+			pc->error = IDETAPE_ERROR_EOD;
+			set_bit (PC_ABORT, &pc->flags);
+		}
+	}
+	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
+		if (result->sense_key == 8) {
+			pc->error = IDETAPE_ERROR_EOD;
+			set_bit (PC_ABORT, &pc->flags);
+		}
+		if (!test_bit (PC_ABORT, &pc->flags) && pc->actually_transferred)
+			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
+	}
 }
 
-void idetape_create_locate_cmd (idetape_packet_command_t *pc,unsigned long block,byte partition)
-
+static void idetape_request_sense_callback (ide_drive_t *drive)
 {
-	unsigned long *ptr;
+	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating LOCATE packet command\n");
+	printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->buffer_size=0;
-	pc->wait_for_dsc=1;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-		
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_LOCATE_CMD;
-	pc->c [1]=2;
-	ptr=(unsigned long *) &(pc->c[3]);
-	*ptr=idetape_swap_long (block);
-	pc->c[8]=partition;
+	if (!tape->pc->error) {
+		idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request (1,HWGROUP (drive));
+	} else {
+		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+		idetape_end_request (0,HWGROUP (drive));
+	}
 }
 
-void idetape_create_rewind_cmd (idetape_packet_command_t *pc)
-
+/*
+ *	idetape_init_pc initializes a packet command.
+ */
+static void idetape_init_pc (idetape_pc_t *pc)
 {
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating REWIND packet command\n");
-#endif /* IDETAPE_DEBUG_LOG */
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->buffer_size=0;
-	pc->wait_for_dsc=1;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-		
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_REWIND_CMD;
+	memset (pc->c, 0, 12);
+	pc->retries = 0;
+	pc->flags = 0;
+	pc->request_transfer = 0;
+	pc->buffer = pc->pc_buffer;
+	pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
+	pc->bh = NULL;
+	pc->b_data = NULL;
+}
+
+static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
+{
+	idetape_init_pc (pc);	
+	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
+	pc->c[4] = 255;
+	pc->request_transfer = 18;
+	pc->callback = &idetape_request_sense_callback;
 }
 
 /*
- *	A mode sense command is used to "sense" tape parameters.
+ *	idetape_retry_pc is called when an error was detected during the
+ *	last packet command. We queue a request sense packet command in
+ *	the head of the request list.
  */
-
-void idetape_create_mode_sense_cmd (idetape_packet_command_t *pc,byte page_code)
-
+static void idetape_retry_pc (ide_drive_t *drive)
 {
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating MODE SENSE packet command - Page %d\n",page_code);
-#endif /* IDETAPE_DEBUG_LOG */
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t *pc;
+	struct request *rq;
+	idetape_error_reg_t error;
 
-	pc->wait_for_dsc=0;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-
-	switch (page_code) {
-		case IDETAPE_CAPABILITIES_PAGE:
-			pc->request_transfer=24;
-	}
-		
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_MODE_SENSE_CMD;
-	pc->c [1]=8;				/* DBD = 1 - Don't return block descriptors for now */
-	pc->c [2]=page_code;
-	pc->c [3]=255;				/* Don't limit the returned information */
-	pc->c [4]=255;				/* (We will just discard data in that case) */
+	error.all = IN_BYTE (IDE_ERROR_REG);
+	pc = idetape_next_pc_storage (drive);
+	rq = idetape_next_rq_storage (drive);
+	idetape_create_request_sense_cmd (pc);
+	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+	idetape_queue_pc_head (drive, pc, rq);
 }
 
 /*
- *	idetape_create_write_filemark_cmd will:
- *
- *		1.	Write a filemark if write_filemark=1.
- *		2.	Flush the device buffers without writing a filemark
- *			if write_filemark=0.
+ *	idetape_pc_intr is the usual interrupt handler which will be called
+ *	during a packet command. We will transfer some of the data (as
+ *	requested by the drive) and will re-point interrupt handler to us.
+ *	When data transfer is finished, we will act according to the
+ *	algorithm described before idetape_issue_packet_command.
  *
  */
- 
-void idetape_create_write_filemark_cmd (idetape_packet_command_t *pc,int write_filemark)
-
+static void idetape_pc_intr (ide_drive_t *drive)
 {
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_status_reg_t status;
+	idetape_bcount_reg_t bcount;
+	idetape_ireason_reg_t ireason;
+	idetape_pc_t *pc=tape->pc;
+	unsigned int temp;
+
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
+#endif /* IDETAPE_DEBUG_LOG */	
+
+#ifdef CONFIG_BLK_DEV_TRITON
+	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
+			set_bit (PC_DMA_ERROR, &pc->flags);
+			/*
+			 *	We will currently correct the following in
+			 *	idetape_analyze_error.
+			 */
+			pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive);
+		} else {
+			pc->actually_transferred=pc->request_transfer;
+			idetape_update_buffers (pc);
+		}
+		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));	/* End DMA */
 #if IDETAPE_DEBUG_LOG
-	printk ("Creating WRITE FILEMARK packet command\n");
-	if (!write_filemark)
-		printk ("which will only flush buffered data\n");
+		printk (KERN_INFO "ide-tape: DMA finished\n");
 #endif /* IDETAPE_DEBUG_LOG */
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->buffer_size=0;
-	pc->wait_for_dsc=1;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-		
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_WRITE_FILEMARK_CMD;
-	if (write_filemark)
-		pc->c [4]=1;
-}
+	}
+#endif /* CONFIG_BLK_DEV_TRITON */
 
-void idetape_create_load_unload_cmd (idetape_packet_command_t *pc,int cmd)
+	status.all = GET_STAT();					/* Clear the interrupt */
 
-{
+	if (!status.b.drq) {						/* No more interrupts */
 #if IDETAPE_DEBUG_LOG
-	printk ("Creating LOAD UNLOAD packet command, cmd=%d\n",cmd);
+		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 #endif /* IDETAPE_DEBUG_LOG */
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->buffer_size=0;
-	pc->wait_for_dsc=1;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-		
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_LOAD_UNLOAD_CMD;
-	pc->c [4]=cmd;
-}
+		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
 
-void idetape_create_erase_cmd (idetape_packet_command_t *pc)
-
-{
+		ide_sti();
 
+		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
 #if IDETAPE_DEBUG_LOG
-	printk ("Creating ERASE command\n");
+			printk (KERN_INFO "ide-tape: %s: I/O error, ",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");
+				ide_do_reset (drive);
+				return;
+			}
+			idetape_retry_pc (drive);				/* Retry operation */
+			return;
+		}
+		pc->error = 0;
+		if (test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
+			tape->dsc_polling_start = jiffies;
+			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
+			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
+			return;
+		}
+		if (tape->failed_pc == pc)
+			tape->failed_pc=NULL;
+		pc->callback(drive);			/* Command finished - Call the callback function */
+		return;
+	}
+#ifdef CONFIG_BLK_DEV_TRITON
+	if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
+		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+		drive->using_dma=0;
+		ide_do_reset (drive);
+		return;
+	}
+#endif /* CONFIG_BLK_DEV_TRITON */
+	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
+	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);				/* on this interrupt */
+	ireason.all=IN_BYTE (IDE_IREASON_REG);
 
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->buffer_size=0;
-	pc->wait_for_dsc=1;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-		
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_ERASE_CMD;
-	pc->c [1]=1;
-}
-
-void idetape_create_read_cmd (idetape_packet_command_t *pc,unsigned long length)
-
-{
-	union convert {
-		unsigned all	:32;
-		struct {
-			unsigned b1	:8;
-			unsigned b2	:8;
-			unsigned b3	:8;
-			unsigned b4	:8;
-		} b;
-	} original;
-	
+	if (ireason.b.cod) {
+		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+		ide_do_reset (drive);
+		return;
+	}
+	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
+		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
+		printk (KERN_ERR "but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
+		ide_do_reset (drive);
+		return;
+	}
+	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+		temp = pc->actually_transferred + bcount.all;
+		if ( temp > pc->request_transfer) {
+			if (temp > pc->buffer_size) {
+				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+				idetape_discard_data (drive,bcount.all);
+				ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);
+				return;
+			}
 #if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating READ packet command\n");
+			printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
 #endif /* IDETAPE_DEBUG_LOG */
+		}
+	}
+	if (test_bit (PC_WRITING, &pc->flags)) {
+		if (pc->bh != NULL)
+			idetape_output_buffers (drive, pc, bcount.all);
+		else
+			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+	} else {
+		if (pc->bh != NULL)
+			idetape_input_buffers (drive, pc, bcount.all);
+		else
+			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+	}
+	pc->actually_transferred+=bcount.all;					/* Update the current position */
+	pc->current_position+=bcount.all;
+
+	ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);		/* And set the interrupt handler again */
+}
+
+/*
+ *	Packet Command Interface
+ *
+ *	The current Packet Command is available in tape->pc, and will not
+ *	change until we finish handling it. Each packet command is associated
+ *	with a callback function that will be called when the command is
+ *	finished.
+ *
+ *	The handling will be done in three stages:
+ *
+ *	1.	idetape_issue_packet_command will send the packet command to the
+ *		drive, and will set the interrupt handler to idetape_pc_intr.
+ *
+ *	2.	On each interrupt, idetape_pc_intr will be called. This step
+ *		will be repeated until the device signals us that no more
+ *		interrupts will be issued.
+ *
+ *	3.	ATAPI Tape media access commands have immediate status with a
+ *		delayed process. In case of a successful initiation of a
+ *		media access packet command, the DSC bit will be set when the
+ *		actual execution of the command is finished. 
+ *		Since the tape drive will not issue an interrupt, we have to
+ *		poll for this event. In this case, we define the request as
+ *		"low priority request" by setting rq_status to
+ *		IDETAPE_RQ_POSTPONED, 	set a timer to poll for DSC and exit
+ *		the driver.
+ *
+ *		ide.c will then give higher priority to requests which
+ *		originate from the other device, until will change rq_status
+ *		to RQ_ACTIVE.
+ *
+ *	4.	When the packet command is finished, it will be checked for errors.
+ *
+ *	5.	In case an error was found, we queue a request sense packet command
+ *		in front of the request queue and retry the operation up to
+ *		IDETAPE_MAX_PC_RETRIES times.
+ *
+ *	6.	In case no error was found, or we decided to give up and not
+ *		to retry again, the callback function will be called and then
+ *		we will handle the next request.
+ *
+ */
+static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_bcount_reg_t bcount;
+	idetape_ireason_reg_t ireason;
+	int dma_ok=0;
+
+#if IDETAPE_DEBUG_BUGS
+	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
+	}
+#endif /* IDETAPE_DEBUG_BUGS */
+
+	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
+		tape->failed_pc=pc;
+	tape->pc=pc;							/* Set the current packet command */
 
-	original.all=length;
+	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+		/*
+		 *	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).
+		 */
+		if (!test_bit (PC_ABORT, &pc->flags)) {
+			printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+				tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
+			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
+		}
+		tape->failed_pc=NULL;
+		pc->callback(drive);
+		return;
+	}
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Retry number - %d\n",pc->retries);
+#endif /* IDETAPE_DEBUG_LOG */
 
-	pc->wait_for_dsc=0;
-	pc->callback=&idetape_read_callback;
-	pc->writing=0;
+	pc->retries++;
+	pc->actually_transferred=0;					/* We haven't transferred any data yet */
+	pc->current_position=pc->buffer;
+	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
 
-	idetape_zero_packet_command (pc);
+#ifdef CONFIG_BLK_DEV_TRITON
+	if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
+		drive->using_dma=0;
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_TRITON */
 
-	pc->c [0]=IDETAPE_READ_CMD;
-	pc->c [1]=1;
-	pc->c [4]=original.b.b1;
-	pc->c [3]=original.b.b2;
-	pc->c [2]=original.b.b3;
+	OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);			/* Use PIO/DMA */
+	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 (length)
-		pc->dma_recommended=1;
+	ide_set_handler (drive, &idetape_pc_intr, WAIT_CMD);		/* Set the interrupt routine */
+	OUT_BYTE (WIN_PACKETCMD,IDE_COMMAND_REG);			/* Issue the packet command */
 
-	return;
+	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { 	/* Wait for DRQ to be ready - Assuming Accelerated DRQ */
+		/*
+		 *	We currently only support tape drives which report
+		 *	accelerated DRQ assertion. For this case, specs
+		 *	allow up to 50us. We really shouldn't get here.
+		 *
+		 *	??? Still needs to think what to do if we reach
+		 *	here anyway.
+		 */
+		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+		return;
+	}
+	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
+		ide_do_reset (drive);
+		return;
+	}
+	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+#ifdef CONFIG_BLK_DEV_TRITON
+	if (dma_ok) {						/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_TRITON */
 }
 
-void idetape_create_space_cmd (idetape_packet_command_t *pc,long count,byte cmd)
+static void idetape_media_access_finished (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t *pc = tape->pc;
+	idetape_status_reg_t status;
+
+	status.all = GET_STAT();
+	if (status.b.dsc) {
+		if (status.b.check) {					/* Error detected */
+			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
+			idetape_retry_pc (drive);			/* Retry operation */
+			return;
+		}
+		pc->error = 0;
+		if (tape->failed_pc == pc)
+			tape->failed_pc = NULL;
+	} else {
+		pc->error = IDETAPE_ERROR_GENERAL;
+		tape->failed_pc = NULL;
+	}
+	pc->callback (drive);
+}
 
+/*
+ *	General packet command callback function.
+ */
+static void idetape_pc_callback (ide_drive_t *drive)
 {
-	union convert {
-		unsigned all	:32;
-		struct {
-			unsigned b1	:8;
-			unsigned b2	:8;
-			unsigned b3	:8;
-			unsigned b4	:8;
-		} b;
-	} original;
+	idetape_tape_t *tape = drive->driver_data;
 	
 #if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating SPACE packet command\n");
+	printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	original.all=count;
+	idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
+}
 
-	pc->request_transfer=0;
-	pc->buffer=NULL;
-	pc->current_position=NULL;
-	pc->buffer_size=0;
-	pc->wait_for_dsc=1;
-	pc->callback=&idetape_pc_callback;
-	pc->writing=0;
-
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_SPACE_CMD;
-	pc->c [1]=cmd;
-	pc->c [4]=original.b.b1;
-	pc->c [3]=original.b.b2;
-	pc->c [2]=original.b.b3;
-
-	return;
-}
-
-void idetape_create_write_cmd (idetape_packet_command_t *pc,unsigned long length)
-
-{
-	union convert {
-		unsigned all	:32;
-		struct {
-			unsigned b1	:8;
-			unsigned b2	:8;
-			unsigned b3	:8;
-			unsigned b4	:8;
-		} b;
-	} original;
-	
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating WRITE packet command\n");
+static void idetape_rw_callback (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	struct request *rq = HWGROUP(drive)->rq;
+	int blocks = tape->pc->actually_transferred / tape->tape_block_size;
+
+#if IDETAPE_DEBUG_LOG	
+	printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	original.all=length;
+	tape->block_address += blocks;
+	rq->current_nr_sectors -= blocks;
 
-	pc->wait_for_dsc=0;
-	pc->callback=&idetape_write_callback;
-	pc->writing=1;
+	if (!tape->pc->error)
+		idetape_end_request (1, HWGROUP (drive));
+	else
+		idetape_end_request (tape->pc->error, HWGROUP (drive));
+}
 
-	idetape_zero_packet_command (pc);
+static void idetape_create_locate_cmd (idetape_pc_t *pc, unsigned int block, byte partition)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_LOCATE_CMD;
+	pc->c[1] = 2;
+	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
+	pc->c[8] = partition;
+	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
+}
 
-	pc->c [0]=IDETAPE_WRITE_CMD;
-	pc->c [1]=1;
-	pc->c [4]=original.b.b1;
-	pc->c [3]=original.b.b2;
-	pc->c [2]=original.b.b3;
+static void idetape_create_rewind_cmd (idetape_pc_t *pc)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_REWIND_CMD;
+	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
+}
 
-	if (length)
-		pc->dma_recommended=1;
+/*
+ *	A mode sense command is used to "sense" tape parameters.
+ */
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
+	pc->c[1] = 8;				/* DBD = 1 - Don't return block descriptors for now */
+	pc->c[2] = page_code;
+	pc->c[3] = 255;				/* Don't limit the returned information */
+	pc->c[4] = 255;				/* (We will just discard data in that case) */
+	if (page_code == IDETAPE_CAPABILITIES_PAGE)
+		pc->request_transfer = 24;
+#if IDETAPE_DEBUG_BUGS
+	else
+		printk (KERN_ERR "ide-tape: unsupported page code in create_mode_sense_cmd\n");
+#endif /* IDETAPE_DEBUG_BUGS */
+	pc->callback = &idetape_pc_callback;
+}
 
-	return;
+/*
+ *	idetape_create_write_filemark_cmd will:
+ *
+ *		1.	Write a filemark if write_filemark=1.
+ *		2.	Flush the device buffers without writing a filemark
+ *			if write_filemark=0.
+ *
+ */
+static void idetape_create_write_filemark_cmd (idetape_pc_t *pc,int write_filemark)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
+	pc->c[4] = write_filemark;
+	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
 }
 
-void idetape_create_read_position_cmd (idetape_packet_command_t *pc)
+static void idetape_create_load_unload_cmd (idetape_pc_t *pc,int cmd)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
+	pc->c[4] = cmd;
+	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
+}
 
+static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Creating READ POSITION packet command\n");
-#endif /* IDETAPE_DEBUG_LOG */
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_ERASE_CMD;
+	pc->c[1] = 1;
+	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
+}
 
-	pc->request_transfer=20;
-	pc->wait_for_dsc=0;
-	pc->callback=&idetape_read_position_callback;
-	pc->writing=0;
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_READ_CMD;
+	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	pc->c[1] = 1;
+	pc->callback = &idetape_rw_callback;
+	pc->bh = bh;
+	bh->b_count = 0;
+	pc->buffer = NULL;
+	pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+	if (pc->request_transfer == tape->stage_size)
+		set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+}
 
-	idetape_zero_packet_command (pc);
-	pc->c [0]=IDETAPE_READ_POSITION_CMD;
-	pc->c [1]=0;
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_SPACE_CMD;
+	put_unaligned (htonl (count), (unsigned int *) &pc->c[1]);
+	pc->c[1] = cmd;
+	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	pc->callback = &idetape_pc_callback;
 }
 
-void idetape_read_position_callback (ide_drive_t *drive)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+{
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_WRITE_CMD;
+	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	pc->c[1] = 1;
+	pc->callback = &idetape_rw_callback;
+	set_bit (PC_WRITING, &pc->flags);
+	pc->bh = bh;
+	pc->b_data = bh->b_data;
+	pc->b_count = bh->b_count;
+	pc->buffer = NULL;
+	pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+	if (pc->request_transfer == tape->stage_size)
+		set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+}
 
+static void idetape_read_position_callback (ide_drive_t *drive)
 {
-	idetape_tape_t *tape;
-	struct request *rq;
+	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
 	
-	tape=&(drive->tape);
-	
 #if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: Reached idetape_read_position_callback\n");
+	printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	rq=HWGROUP(drive)->rq;
-	
 	if (!tape->pc->error) {
-		result=(idetape_read_position_result_t *) tape->pc->buffer;
+		result = (idetape_read_position_result_t *) tape->pc->buffer;
 #if IDETAPE_DEBUG_LOG
-		printk ("Request completed\n");
-		printk ("Dumping the results of the READ POSITION command\n");
-		printk ("BOP - %s\n",result->bop ? "Yes":"No");
-		printk ("EOP - %s\n",result->eop ? "Yes":"No");
+		printk (KERN_INFO "BOP - %s\n",result->bop ? "Yes":"No");
+		printk (KERN_INFO "EOP - %s\n",result->eop ? "Yes":"No");
 #endif /* IDETAPE_DEBUG_LOG */
 		if (result->bpu) {
-			printk ("ide-tape: Block location is unknown to the tape\n");
-			printk ("Aborting request\n");
-			tape->block_address_valid=0;
+			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
 			idetape_end_request (0,HWGROUP (drive));
-		}
-		else {
+		} else {
 #if IDETAPE_DEBUG_LOG
-			printk ("Block Location - %lu\n",idetape_swap_long (result->first_block));
+			printk (KERN_INFO "Block Location - %lu\n", ntohl (result->first_block));
 #endif /* IDETAPE_DEBUG_LOG */
-			tape->block_address=idetape_swap_long (result->first_block);
-			tape->block_address_valid=1;
+			tape->partition = result->partition;
+			tape->block_address = ntohl (result->first_block);
+			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
 			idetape_end_request (1,HWGROUP (drive));
 		}
-	}
-	else {
-		printk ("Aborting request\n");
+	} else
 		idetape_end_request (0,HWGROUP (drive));
-	}
-	return;
-}
-
-/*
- *	Our special ide-tape ioctl's.
- *
- *	Currently there aren't any significant ioctl's.
- *	mtio.h compatible commands should be issued to the character device
- *	interface.
- */
- 
-int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	idetape_packet_command_t pc;
-	
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
-
-#if IDETAPE_DEBUG_LOG	
-	printk ("ide-tape: Reached idetape_blkdev_ioctl\n");
-#endif /* IDETAPE_DEBUG_LOG */
-	switch (cmd) {
-		default:
-			return -EIO;
-	}
 }
 
-/*
- *	Functions which handle requests.
- */
-
-/*
- *	idetape_end_request is used to end a request.
- */
-
-void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
-
+static void idetape_create_read_position_cmd (idetape_pc_t *pc)
 {
-	ide_drive_t *drive = hwgroup->drive;
-	struct request *rq = hwgroup->rq;
-	idetape_tape_t *tape = &(drive->tape);
-	unsigned int major = HWIF(drive)->major;
-	struct blk_dev_struct *bdev = &blk_dev[major];
-	int error;
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_end_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-	bdev->current_request=rq;			/* Since we may have taken it out */
-
-	if (!rq->errors)				/* In case rq->errors is already set, */
-		rq->errors=!uptodate;			/* we won't change it. */
-	error=rq->errors;
-		
-	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
-
-		if (rq->cmd == IDETAPE_READ_REQUEST) {
-#if IDETAPE_DEBUG_BUGS
-			if (tape->active_stage == NULL)
-				printk ("ide-tape: bug: active_stage is NULL in idetape_end_request\n");
-			else				
-#endif /* IDETAPE_DEBUG_BUGS */
-			idetape_copy_buffer_to_stage (tape->active_stage,tape->data_buffer);
-		}
-
-		tape->active_stage=NULL;
-		tape->active_data_request=NULL;
-
-		if (rq->cmd == IDETAPE_WRITE_REQUEST) {
-			if (rq->errors)
-				tape->error_in_pipeline_stage=rq->errors;
-			idetape_remove_stage_head (drive);
-		}
-		
-		if (tape->next_stage == NULL) {
-			if (!error)
-				idetape_increase_max_pipeline_stages (drive);
-			ide_end_drive_cmd (drive, 0, 0);
-			return;
-		}
-
-		idetape_active_next_stage (drive);
-
-		/*
-		 *	Insert the next request into the request queue.
-		 *
-		 *	The choice of using ide_next or ide_end is now left
-		 *	to the user.
-		 */
-		 
-#if IDETAPE_LOW_TAPE_PRIORITY
-		(void) ide_do_drive_cmd (drive,tape->active_data_request,ide_end);
-#else
-		(void) ide_do_drive_cmd (drive,tape->active_data_request,ide_next);
-#endif /* IDETAPE_LOW_TAPE_PRIORITY */
-	}
-	ide_end_drive_cmd (drive, 0, 0);
+	idetape_init_pc (pc);
+	pc->c[0] = IDETAPE_READ_POSITION_CMD;
+	pc->request_transfer = 20;
+	pc->callback = &idetape_read_position_callback;
 }
 
 /*
  *	idetape_do_request is our request handling function.	
  */
-
-void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
-
+static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_packet_command_t *pc;
-	unsigned int major = HWIF(drive)->major;
-	struct blk_dev_struct *bdev = &blk_dev[major];
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t *pc;
+	struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major];
+	struct request *postponed_rq = tape->postponed_rq;
 	idetape_status_reg_t status;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("Current request:\n");
-	printk ("rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk ("sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_REQUEST_CMD (rq->cmd)) {
-
+	if (!IDETAPE_RQ_CMD (rq->cmd)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-
-		printk ("ide-tape: Unsupported command in request queue\n");
-		printk ("ide-tape: The block device interface should not be used for data transfers.\n");
-		printk ("ide-tape: Use the character device interfaces\n");
-		printk ("ide-tape: /dev/ht0 and /dev/nht0 instead.\n");
-		printk ("ide-tape: (Run linux/scripts/MAKEDEV.ide to create them)\n");
-		printk ("ide-tape: Aborting request.\n");
-
+		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue\n", drive->name);
 		ide_end_request (0,HWGROUP (drive));			/* Let the common code handle it */
 		return;
 	}
@@ -2980,131 +2278,81 @@
 	 *
 	 *	The potential fragmentation inefficiency was pointed to me
 	 *	by Mark Lord.
+	 *
+	 *	Uhuh.. the following "fix" is actually not entirely correct.
+	 *	Some day we should probably move to a per device request
+	 *	queue, rather than per interface.
 	 */
-	 
 	if (rq->next != NULL && rq->rq_dev != rq->next->rq_dev)
 		bdev->current_request=rq->next;
 
-	/* Retry a failed packet command */
-
+	/*
+	 *	Retry a failed packet command
+	 */
 	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		idetape_issue_packet_command (drive,tape->failed_pc,&idetape_pc_intr);
+		idetape_issue_packet_command (drive, tape->failed_pc);
 		return;
 	}
-
-	/* Check if we have a postponed request */
-	
-	if (tape->postponed_rq != NULL) {
 #if IDETAPE_DEBUG_BUGS
-		if (tape->postponed_rq->rq_status != RQ_ACTIVE || rq != tape->postponed_rq) {
-			printk ("ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
+	if (postponed_rq != NULL)
+		if (postponed_rq->rq_status != RQ_ACTIVE || rq != postponed_rq) {
+			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
 			idetape_end_request (0,HWGROUP (drive));
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		if (rq->cmd == IDETAPE_PACKET_COMMAND_REQUEST_TYPE1) {
-	
-			/* Media access command */
-			
-			tape->postponed_rq = NULL;
-			idetape_media_access_finished (drive);
-			return;
-		}
-		
-		/*
-		 * Read / Write command - DSC polling was done before the
-		 * actual command - Continue normally so that the command
-		 * will be performed below.
-		 */
-		 
-		 tape->postponed_rq = NULL;
-	}	
 
-	status.all=IN_BYTE (IDETAPE_STATUS_REG);
+	tape->postponed_rq = NULL;
 
 	/*
-	 *	After a software reset, the status register is locked. We
-	 *	will ignore the DSC value for our very first packet command,
-	 *	which will restore DSC operation.
+	 *	If the tape is still busy, postpone our request and service
+	 *	the other device meanwhile.
 	 */
-
-	if (tape->reset_issued) {
-		status.b.dsc=1;
-		tape->reset_issued=0;
+	status.all = GET_STAT();
+	if (!clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+		if (postponed_rq == NULL) {
+			tape->dsc_polling_start = jiffies;
+			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
+			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
+		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
+			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
+			if (rq->cmd == IDETAPE_PC_RQ)
+				idetape_media_access_finished (drive);
+			else
+				ide_do_reset (drive);
+			return;
+		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
+			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
+		idetape_postpone_request (drive);
+		return;
 	}
-	
 	switch (rq->cmd) {
-		case IDETAPE_READ_REQUEST:
-			if (!status.b.dsc) {				/* Tape buffer not ready to accept r/w command */
-#if IDETAPE_DEBUG_LOG
-				printk ("ide-tape: DSC != 1 - Postponing read request\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-				tape->dsc_polling_frequency=tape->best_dsc_rw_frequency;
-				idetape_postpone_request (drive);	/* Allow ide.c to process requests from */
-				return;
-			}			
-
+		case IDETAPE_READ_RQ:
 			pc=idetape_next_pc_storage (drive);
-
-			idetape_create_read_cmd (pc,rq->current_nr_sectors);
-			
-			pc->buffer=rq->buffer;
-			pc->buffer_size=rq->current_nr_sectors*tape->tape_block_size;
-			pc->current_position=rq->buffer;
-			pc->request_transfer=rq->current_nr_sectors*tape->tape_block_size;
-
-			idetape_issue_packet_command (drive,pc,&idetape_pc_intr);
-			return;
-		
-		case IDETAPE_WRITE_REQUEST:
-			if (!status.b.dsc) {				/* Tape buffer not ready to accept r/w command */
-#if IDETAPE_DEBUG_LOG
-				printk ("ide-tape: DSC != 1 - Postponing write request\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-				tape->dsc_polling_frequency=tape->best_dsc_rw_frequency;
-				idetape_postpone_request (drive);	/* Allow ide.c to process requests from */
-				return;
-			}			
-
+			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			break;
+		case IDETAPE_WRITE_RQ:
 			pc=idetape_next_pc_storage (drive);
-
-			idetape_create_write_cmd (pc,rq->current_nr_sectors);
-			
-			pc->buffer=rq->buffer;
-			pc->buffer_size=rq->current_nr_sectors*tape->tape_block_size;
-			pc->current_position=rq->buffer;
-			pc->request_transfer=rq->current_nr_sectors*tape->tape_block_size;
-
-			idetape_issue_packet_command (drive,pc,&idetape_pc_intr);
+			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			break;
+		case IDETAPE_ABORTED_WRITE_RQ:
+			rq->cmd = IDETAPE_WRITE_RQ;
+			rq->errors = IDETAPE_ERROR_EOD;
+			idetape_end_request (1, HWGROUP(drive));
 			return;
-					
-		case IDETAPE_PACKET_COMMAND_REQUEST_TYPE1:
-		case IDETAPE_PACKET_COMMAND_REQUEST_TYPE2:
-/*
- *	This should be unnecessary (postponing of a general packet command),
- *	but I have occasionally missed DSC on a media access command otherwise.
- *	??? Still have to figure it out ...
- */
-			if (!status.b.dsc) {				/* Tape buffers are still not ready */
-#if IDETAPE_DEBUG_LOG
-				printk ("ide-tape: DSC != 1 - Postponing packet command request\n");
-#endif /* IDETAPE_DEBUG_LOG */
-				rq->cmd=IDETAPE_PACKET_COMMAND_REQUEST_TYPE2;	/* Note that we are waiting for DSC *before* we */
-										/* even issued the command */
-				tape->dsc_polling_frequency=IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY;
-				idetape_postpone_request (drive);	/* Allow ide.c to process requests from */
+		case IDETAPE_PC_RQ:
+			if (postponed_rq != NULL) {
+				idetape_media_access_finished (drive);
 				return;
 			}
-			rq->cmd=IDETAPE_PACKET_COMMAND_REQUEST_TYPE1;
-			pc=(idetape_packet_command_t *) rq->buffer;
-			idetape_issue_packet_command (drive,pc,&idetape_pc_intr);
-			return;
-#if IDETAPE_DEBUG_BUGS
+			pc=(idetape_pc_t *) rq->buffer;
+			break;
 		default:
-			printk ("ide-tape: bug in IDETAPE_REQUEST_CMD macro\n");
+			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
 			idetape_end_request (0,HWGROUP (drive));
-#endif /* IDETAPE_DEBUG_BUGS */
-	}	
+			return;
+	}
+	idetape_issue_packet_command (drive, pc);
 }
 
 /*
@@ -3127,72 +2375,34 @@
  *	the request to the request list without waiting for it to be serviced !
  *	In that case, we usually use idetape_queue_pc_head.
  */
-
-int idetape_queue_pc_tail (ide_drive_t *drive,idetape_packet_command_t *pc)
+static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
 {
 	struct request rq;
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
-	rq.cmd = IDETAPE_PACKET_COMMAND_REQUEST_TYPE1;
+	rq.cmd = IDETAPE_PC_RQ;
 	return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
 /*
- *	idetape_queue_pc_head generates a new packet command request in front
- *	of the request queue, before the current request, so that it will be
- *	processed immediately, on the next pass through the driver.
- *
- *	idetape_queue_pc_head is called from the request handling part of
- *	the driver (the "bottom" part). Safe storage for the request should
- *	be allocated with idetape_next_pc_storage and idetape_next_rq_storage
- *	before calling idetape_queue_pc_head.
- *
- *	Memory for those requests is pre-allocated at initialization time, and
- *	is limited to IDETAPE_PC_STACK requests. We assume that we have enough
- *	space for the maximum possible number of inter-dependent packet commands.
- *
- *	The higher level of the driver - The ioctl handler and the character
- *	device handling functions should queue request to the lower level part
- *	and wait for their completion using idetape_queue_pc_tail or
- *	idetape_queue_rw_tail.
- */
- 
-void idetape_queue_pc_head (ide_drive_t *drive,idetape_packet_command_t *pc,struct request *rq)
-
-{
-	unsigned int major = HWIF(drive)->major;
-	struct blk_dev_struct *bdev = &blk_dev[major];
-
-	bdev->current_request=HWGROUP (drive)->rq;		/* Since we may have taken it out */
-
-	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
-	rq->cmd = IDETAPE_PACKET_COMMAND_REQUEST_TYPE1;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
-}
-
-/*
  *	idetape_wait_for_request installs a semaphore in a pending request
  *	and sleeps until it is serviced.
  *
  *	The caller should ensure that the request will not be serviced
  *	before we install the semaphore (usually by disabling interrupts).
  */
- 
-void idetape_wait_for_request (struct request *rq)
-
+static void idetape_wait_for_request (struct request *rq)
 {
 	struct semaphore sem = MUTEX_LOCKED;
 
 #if IDETAPE_DEBUG_BUGS
-	if (rq == NULL || !IDETAPE_REQUEST_CMD (rq->cmd)) {
-		printk ("ide-tape: bug: Trying to sleep on non-valid request\n");
-		return;		
+	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
+		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
-
-	rq->sem=&sem;
+	rq->sem = &sem;
 	down (&sem);
 }
 
@@ -3200,93 +2410,93 @@
  *	idetape_queue_rw_tail generates a read/write request for the block
  *	device interface and wait for it to be serviced.
  */
-
-int idetape_queue_rw_tail (ide_drive_t *drive,int cmd,int blocks,char *buffer)
-
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
 {
-	idetape_tape_t *tape = &(drive->tape);
+	idetape_tape_t *tape = drive->driver_data;
 	struct request rq;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("idetape_queue_rw_tail: cmd=%d\n",cmd);
+	printk (KERN_INFO "idetape_queue_rw_tail: cmd=%d\n",cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
-	if (tape->active_data_request != NULL) {
-		printk ("ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+	if (idetape_pipeline_active (tape)) {
+		printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
 		return (0);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	ide_init_drive_cmd (&rq);
-	rq.buffer = buffer;
+	rq.bh = bh;
 	rq.cmd = cmd;
 	rq.sector = tape->block_address;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
 
-	return (tape->tape_block_size*(blocks-rq.current_nr_sectors));
+	idetape_init_merge_stage (tape);
+	if (rq.errors == IDETAPE_ERROR_GENERAL)
+		return -EIO;
+	return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
 }
 
 /*
- *	idetape_add_chrdev_read_request handles character device read requests
- *	when operating in the pipelined operation mode.
+ *	idetape_add_chrdev_read_request is called from idetape_chrdev_read
+ *	to service a character device read request and add read-ahead
+ *	requests to our pipeline.
  */
- 
-int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks,char *buffer)
-
+static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
 {
-	idetape_tape_t *tape = &(drive->tape);
-	idetape_pipeline_stage_t *new_stage;
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *new_stage;
 	unsigned long flags;
 	struct request rq,*rq_ptr;
 	int bytes_read;
 	
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_add_chrdev_read_request\n");
+	printk (KERN_INFO "Reached idetape_add_chrdev_read_request\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	ide_init_drive_cmd (&rq);
-	rq.cmd = IDETAPE_READ_REQUEST;
+	rq.cmd = IDETAPE_READ_RQ;
 	rq.sector = tape->block_address;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 
-	if (tape->active_data_request != NULL || tape->current_number_of_stages <= tape->max_number_of_stages / 4) {
-		new_stage=idetape_kmalloc_stage (drive);
+	if (idetape_pipeline_active (tape) || tape->nr_stages <= tape->max_stages / 4) {
+		new_stage=idetape_kmalloc_stage (tape);
 		while (new_stage != NULL) {
 			new_stage->rq=rq;
-			save_flags (flags);cli ();
 			idetape_add_stage_tail (drive,new_stage);
-			restore_flags (flags);
-			new_stage=idetape_kmalloc_stage (drive);
+			new_stage=idetape_kmalloc_stage (tape);
 		}
-		if (tape->active_data_request == NULL)
+		if (!idetape_pipeline_active (tape))
 			idetape_insert_pipeline_into_queue (drive);
 	}
-
 	if (tape->first_stage == NULL) {
-
 		/*
 		 *	Linux is short on memory. Revert to non-pipelined
 		 *	operation mode for this request.
 		 */
-		 
-		return (idetape_queue_rw_tail (drive,IDETAPE_READ_REQUEST,blocks,buffer));
-	}		
-	
-	save_flags (flags);cli ();
-	if (tape->active_data_request == &(tape->first_stage->rq))
+		return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh));
+	}
+	save_flags (flags);
+	cli ();
+	if (tape->active_stage == tape->first_stage)
 		idetape_wait_for_request (tape->active_data_request);
 	restore_flags (flags);
 
-	rq_ptr=&(tape->first_stage->rq);
-	bytes_read=tape->tape_block_size*(rq_ptr->nr_sectors-rq_ptr->current_nr_sectors);
-	rq_ptr->nr_sectors=rq_ptr->current_nr_sectors=0;
-	idetape_copy_buffer_from_stage (tape->first_stage,buffer);
-	if (rq_ptr->errors != IDETAPE_RQ_ERROR_FILEMARK)
+	rq_ptr = &tape->first_stage->rq;
+	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
+	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
+
+	idetape_switch_buffers (tape, tape->first_stage);
+
+	if (rq_ptr->errors != IDETAPE_ERROR_FILEMARK) {
+		clear_bit (IDETAPE_FILEMARK, &tape->flags);
 		idetape_remove_stage_head (drive);
+	} else
+		set_bit (IDETAPE_FILEMARK, &tape->flags);
 #if IDETAPE_DEBUG_BUGS
 	if (bytes_read > blocks*tape->tape_block_size) {
-		printk ("ide-tape: bug: trying to return more bytes than requested\n");
+		printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
 		bytes_read=blocks*tape->tape_block_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3304,60 +2514,47 @@
  *	3.	If we still can't allocate a stage, fallback to
  *		non-pipelined operation mode for this request.
  */
-
-int idetape_add_chrdev_write_request (ide_drive_t *drive,int blocks,char *buffer)
-
+static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
 {
-	idetape_tape_t *tape = &(drive->tape);
-	idetape_pipeline_stage_t *new_stage;
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *new_stage;
 	unsigned long flags;
 	struct request *rq;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_add_chrdev_write_request\n");
+	printk (KERN_INFO "Reached idetape_add_chrdev_write_request\n");
 #endif /* IDETAPE_DEBUG_LOG */
-	
-	
-	new_stage=idetape_kmalloc_stage (drive);
 
-	/*
-	 *	If we don't have a new stage, wait for more and more requests
-	 *	to finish, and try to allocate after each one.
-	 *
+     	/*
+     	 *	Attempt to allocate a new stage.
 	 *	Pay special attention to possible race conditions.
 	 */
-
-	while (new_stage == NULL) {
-		save_flags (flags);cli ();
-		if (tape->active_data_request != NULL) {
+	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
+		save_flags (flags);
+		cli ();
+		if (idetape_pipeline_active (tape)) {
 			idetape_wait_for_request (tape->active_data_request);
 			restore_flags (flags);
-			new_stage=idetape_kmalloc_stage (drive);
-		}
-		else {
+		} else {
+			restore_flags (flags);
+			idetape_insert_pipeline_into_queue (drive);
+			if (idetape_pipeline_active (tape))
+				continue;
 			/*
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-	 	 	
-			restore_flags (flags);
-			return (idetape_queue_rw_tail (drive,IDETAPE_WRITE_REQUEST,blocks,buffer));
+			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 		}
 	}
-
-	rq=&(new_stage->rq);
-
+	rq = &new_stage->rq;
 	ide_init_drive_cmd (rq);
-	rq->cmd = IDETAPE_WRITE_REQUEST;
+	rq->cmd = IDETAPE_WRITE_RQ;
 	rq->sector = tape->block_address;	/* Doesn't actually matter - We always assume sequential access */
-	rq->nr_sectors = blocks;
-	rq->current_nr_sectors = blocks;
+	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
-	idetape_copy_buffer_to_stage (new_stage,buffer);
-
-	save_flags (flags);cli ();
+	idetape_switch_buffers (tape, new_stage);
 	idetape_add_stage_tail (drive,new_stage);
-	restore_flags (flags);
 
 	/*
 	 *	Check if we are currently servicing requests in the bottom
@@ -3367,111 +2564,127 @@
 	 *	starting to service requests, so that we will be able to
 	 *	keep up with the higher speeds of the tape.
 	 */
+	if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4)
+		idetape_insert_pipeline_into_queue (drive);
 
-	if (tape->active_data_request == NULL && tape->current_number_of_stages >= (3 * tape->max_number_of_stages) / 4)
-		idetape_insert_pipeline_into_queue (drive);		
-
-	if (tape->error_in_pipeline_stage) {		/* Return a deferred error */
-		tape->error_in_pipeline_stage=0;
-		return (-EIO);
-	}
-	
-	return (blocks);
+	if (clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+		return -EIO;
+	return blocks;
 }
 
-void idetape_discard_read_pipeline (ide_drive_t *drive)
-
+static void idetape_discard_read_pipeline (ide_drive_t *drive)
 {
-	idetape_tape_t *tape = &(drive->tape);
+	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_read) {
-		printk ("ide-tape: bug: Trying to discard read pipeline, but we are not reading.\n");
+		printk (KERN_ERR "ide-tape: bug: Trying to discard read pipeline, but we are not reading.\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
-
-	tape->merge_buffer_size=tape->merge_buffer_offset=0;
-	tape->chrdev_direction=idetape_direction_none;
+	tape->merge_stage_size = 0;
+	if (tape->merge_stage != NULL) {
+		__idetape_kfree_stage (tape->merge_stage);
+		tape->merge_stage = NULL;
+	}
+	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
 		return;
 		
-	save_flags (flags);cli ();
-	tape->next_stage=NULL;
-	if (tape->active_data_request != NULL)
+	save_flags (flags);
+	cli ();
+	tape->next_stage = NULL;
+	if (idetape_pipeline_active (tape))
 		idetape_wait_for_request (tape->active_data_request);
 	restore_flags (flags);
 
 	while (tape->first_stage != NULL)
 		idetape_remove_stage_head (drive);
-
-#if IDETAPE_PIPELINE
-	tape->max_number_of_stages=IDETAPE_MIN_PIPELINE_STAGES;
-#else
-	tape->max_number_of_stages=0;
-#endif /* IDETAPE_PIPELINE */
+	tape->nr_pending_stages = 0;
+	tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES;
 }
 
 /*
  *	idetape_wait_for_pipeline will wait until all pending pipeline
  *	requests are serviced. Typically called on device close.
  */
- 
-void idetape_wait_for_pipeline (ide_drive_t *drive)
-
+static void idetape_wait_for_pipeline (ide_drive_t *drive)
 {
-	idetape_tape_t *tape = &(drive->tape);
+	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 
-	if (tape->active_data_request == NULL)
-		idetape_insert_pipeline_into_queue (drive);		
-
-	save_flags (flags);cli ();
-	if (tape->active_data_request == NULL) {
-		restore_flags (flags);
-		return;
-	}
-	
-	if (tape->last_stage != NULL)
-		idetape_wait_for_request (&(tape->last_stage->rq));
+	if (!idetape_pipeline_active (tape))
+		idetape_insert_pipeline_into_queue (drive);
 
-	else if (tape->active_data_request != NULL)
-		idetape_wait_for_request (tape->active_data_request);
+	save_flags (flags);
+	cli ();
+	if (!idetape_pipeline_active (tape))
+		goto abort;
+#if IDETAPE_DEBUG_BUGS
+	if (tape->last_stage == NULL)
+		printk ("ide-tape: tape->last_stage == NULL\n");
+	else
+#endif /* IDETAPE_DEBUG_BUGS */
+	idetape_wait_for_request (&tape->last_stage->rq);
+abort:
 	restore_flags (flags);
 }
 
-void idetape_empty_write_pipeline (ide_drive_t *drive)
+static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	struct buffer_head *bh;
+	int count, blocks;
+	
+	while (bcount) {
+		bh = tape->merge_stage->bh;
+		count = IDETAPE_MIN (tape->stage_size, bcount);
+		bcount -= count;
+		blocks = count / tape->tape_block_size;
+		while (count) {
+			bh->b_count = IDETAPE_MIN (count, bh->b_size);
+			memset (bh->b_data, 0, bh->b_count);
+			count -= bh->b_count;
+			bh = bh->b_reqnext;
+		}
+		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+	}
+}
 
+static void idetape_empty_write_pipeline (ide_drive_t *drive)
 {
-	idetape_tape_t *tape = &(drive->tape);
-	int blocks;
+	idetape_tape_t *tape = drive->driver_data;
+	int blocks, i;
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
-		printk ("ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+		printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
 		return;
 	}
-	if (tape->merge_buffer_size > tape->data_buffer_size) {
-		printk ("ide-tape: bug: merge_buffer too big\n");
-		tape->merge_buffer_size = tape->data_buffer_size;
+	if (tape->merge_stage_size > tape->stage_size) {
+		printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+		tape->merge_stage_size = tape->stage_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
-
-	if (tape->merge_buffer_size) {
-		blocks=tape->merge_buffer_size/tape->tape_block_size;
-		if (tape->merge_buffer_size % tape->tape_block_size) {
+	if (tape->merge_stage_size) {
+		blocks=tape->merge_stage_size/tape->tape_block_size;
+		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
-			memset (tape->merge_buffer+tape->merge_buffer_size,0,tape->data_buffer_size-tape->merge_buffer_size);
+			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
+			memset (tape->merge_stage->bh->b_data + tape->merge_stage->bh->b_count, 0, i);
+			tape->merge_stage->bh->b_count += i;
 		}
-		(void) idetape_add_chrdev_write_request (drive,blocks,tape->merge_buffer);
-		tape->merge_buffer_size=0;
+		(void) idetape_add_chrdev_write_request (drive, blocks);
+		tape->merge_stage_size = 0;
 	}
-	
 	idetape_wait_for_pipeline (drive);
-
-	tape->error_in_pipeline_stage=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;
 
 	/*
@@ -3480,185 +2693,241 @@
 	 *	 as some systems are constantly on, and the system load
 	 *	 can be totally different on the next backup).
 	 */
+	tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES;
+#if IDETAPE_DEBUG_BUGS
+	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) {
+		printk (KERN_ERR "ide-tape: ide-tape pipeline bug\n");		
+	}
+#endif /* IDETAPE_DEBUG_BUGS */
+}
+
+static int idetape_pipeline_size (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage;
+	struct request *rq;
+	int size = 0;
 
-#if IDETAPE_PIPELINE
-	tape->max_number_of_stages=IDETAPE_MIN_PIPELINE_STAGES;
-#else
-	tape->max_number_of_stages=0;
-#endif /* IDETAPE_PIPELINE */
-#if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->current_number_of_stages != 0) {
-		printk ("ide-tape: ide-tape pipeline bug\n");		
+	idetape_wait_for_pipeline (drive);
+	stage = tape->first_stage;
+	while (stage != NULL) {
+		rq = &stage->rq;
+		size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors);
+		if (rq->errors == IDETAPE_ERROR_FILEMARK)
+			size += tape->tape_block_size;
+		stage = stage->next;
 	}
-#endif /* IDETAPE_DEBUG_BUGS */
+	size += tape->merge_stage_size;
+	return size;
 }
 
 /*
- *	idetape_zero_packet_command just zeros a packet command and
- *	sets the number of retries to 0, as we haven't retried it yet.
+ *	idetape_position_tape positions the tape to the requested block
+ *	using the LOCATE packet command. A READ POSITION command is then
+ *	issued to check where we are positioned.
+ *
+ *	Like all higher level operations, we queue the commands at the tail
+ *	of the request queue and wait for their completion.
+ *	
  */
- 
-void idetape_zero_packet_command (idetape_packet_command_t *pc)
+static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition)
+{
+	int retval;
+	idetape_pc_t pc;
+
+	idetape_create_locate_cmd (&pc, block, partition);
+	retval=idetape_queue_pc_tail (drive,&pc);
+	if (retval) return (retval);
+
+	idetape_create_read_position_cmd (&pc);
+	return (idetape_queue_pc_tail (drive,&pc));
+}
 
+/*
+ *	Rewinds the tape to the Beginning Of the current Partition (BOP).
+ *
+ *	We currently support only one partition.
+ */ 
+static int idetape_rewind_tape (ide_drive_t *drive)
 {
-	int i;
+	int retval;
+	idetape_pc_t pc;
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Reached idetape_rewind_tape\n");
+#endif /* IDETAPE_DEBUG_LOG */	
 	
-	for (i=0;i<12;i++)
-		pc->c[i]=0;
-	pc->retries=0;
-	pc->abort=0;
-	pc->dma_recommended=0;
-	pc->dma_error=0;
+	idetape_create_rewind_cmd (&pc);
+	retval=idetape_queue_pc_tail (drive,&pc);
+	if (retval) return (retval);
+
+	idetape_create_read_position_cmd (&pc);
+	return (idetape_queue_pc_tail (drive,&pc));
+}
+
+static int idetape_flush_tape_buffers (ide_drive_t *drive)
+{
+	idetape_pc_t pc;
+
+	idetape_create_write_filemark_cmd (&pc,0);
+	return (idetape_queue_pc_tail (drive,&pc));
 }
 
 /*
- *	idetape_swap_shorts converts a 16 bit number from little endian
- *	to big endian format.
+ *	Our special ide-tape ioctl's.
+ *
+ *	Currently there aren't any ioctl's.
+ *	mtio.h compatible commands should be issued to the character device
+ *	interface.
  */
- 
-unsigned short idetape_swap_short (unsigned short temp)
-
+static int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
+				 unsigned int cmd, unsigned long arg)
 {
-	union convert {
-		unsigned all	:16;
-		struct {
-			unsigned b1	:8;
-			unsigned b2	:8;
-		} b;
-	} original,converted;
-	
-	original.all=temp;
-	converted.b.b1=original.b.b2;
-	converted.b.b2=original.b.b1;
-	return (converted.all);
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_config_t config;
+
+#if IDETAPE_DEBUG_LOG	
+	printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+#endif /* IDETAPE_DEBUG_LOG */
+	switch (cmd) {
+		case 0x0340:
+			if (copy_from_user ((char *) &config, (char *) arg, sizeof (idetape_config_t)))
+				return -EFAULT;
+			tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
+			tape->max_stages = config.nr_stages;
+			break;
+		case 0x0350:
+			config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
+			config.nr_stages = tape->max_stages; 
+			if (copy_to_user ((char *) arg, (char *) &config, sizeof (idetape_config_t)))
+				return -EFAULT;
+			break;
+		default:
+			return -EIO;
+	}
+	return 0;
 }
 
 /*
- *	idetape_swap_long converts from little endian to big endian format.
+ *	The block device interface should not be used for data transfers.
+ *	However, we still allow opening it so that we can issue general
+ *	ide driver configuration ioctl's, such as the interrupt unmask feature.
  */
- 
-unsigned long idetape_swap_long (unsigned long temp)
-
+static int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
-	union convert {
-		unsigned all	:32;
-		struct {
-			unsigned b1	:8;
-			unsigned b2	:8;
-			unsigned b3	:8;
-			unsigned b4	:8;
-		} b;
-	} original,converted;
-	
-	original.all=temp;
-	converted.b.b1=original.b.b4;
-	converted.b.b2=original.b.b3;
-	converted.b.b3=original.b.b2;
-	converted.b.b4=original.b.b1;
-	return (converted.all);
+	MOD_INC_USE_COUNT;
+	return 0;
 }
 
+static void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
+	MOD_DEC_USE_COUNT;
+}
 
 /*
- *	idetape_next_pc_storage returns a pointer to a place in which we can
- *	safely store a packet command, even though we intend to leave the
- *	driver. A storage space for a maximum of IDETAPE_PC_STACK packet
- *	commands is allocated at initialization time.
+ *	idetape_pre_reset is called before an ATAPI/ATA software reset.
  */
- 
-idetape_packet_command_t *idetape_next_pc_storage (ide_drive_t *drive)
-
+static void idetape_pre_reset (ide_drive_t *drive)
 {
-	idetape_tape_t *tape;
-	
-	tape=&(drive->tape);
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
-	if (tape->pc_stack_index==IDETAPE_PC_STACK)
-		tape->pc_stack_index=0;
-	return (&(tape->pc_stack [tape->pc_stack_index++]));
+	idetape_tape_t *tape = drive->driver_data;
+	if (tape != NULL)
+		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 }
 
 /*
- *	idetape_next_rq_storage is used along with idetape_next_pc_storage.
- *	Since we queue packet commands in the request queue, we need to
- *	allocate a request, along with the allocation of a packet command.
+ *	Character device interface functions
  */
- 
-/**************************************************************
- *                                                            *
- *  This should get fixed to use kmalloc(GFP_ATOMIC, ..)      *
- *  followed later on by kfree().   -ml                       *
- *                                                            *
- **************************************************************/
- 
-struct request *idetape_next_rq_storage (ide_drive_t *drive)
-
+static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
 {
-	idetape_tape_t *tape;
+	unsigned int i = MINOR(i_rdev) & ~0x80;
 	
-	tape=&(drive->tape);
-
-#if IDETAPE_DEBUG_LOG
-	printk ("ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
-	if (tape->rq_stack_index==IDETAPE_PC_STACK)
-		tape->rq_stack_index=0;
-	return (&(tape->rq_stack [tape->rq_stack_index++]));
+	if (i >= MAX_HWIFS * MAX_DRIVES)
+		return NULL;
+	return (idetape_chrdevs[i].drive);
 }
 
 /*
- *	Block device interface functions
+ *	idetape_space_over_filemarks is now a bit more complicated than just
+ *	passing the command to the tape since we may have crossed some
+ *	filemarks during our pipelined read-ahead mode.
  *
- *	The block device interface should not be used for data transfers.
- *	However, we still allow opening it so that we can issue general
- *	ide driver configuration ioctl's, such as the interrupt unmask feature.
+ *	As a minor side effect, the pipeline enables us to support MTFSFM when
+ *	the filemark is in our internal pipeline even if the tape doesn't
+ *	support spacing over filemarks in the reverse direction.
  */
-
-int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
-
+static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
 {
-	idetape_tape_t *tape=&(drive->tape);
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t pc;
 	unsigned long flags;
-			
-	save_flags (flags);cli ();
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_blkdev_open\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-	if (tape->busy) {
-		restore_flags (flags);		/* Allowing access only through one */
-		return (-EBUSY);		/* one file descriptor */
-	}
-
-	tape->busy=1;
-	restore_flags (flags);
-
-	return (0);
-}
+	int retval,count=0;
 
-void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
+	if (tape->chrdev_direction == idetape_direction_read) {
 
-{
-	idetape_tape_t *tape=&(drive->tape);
-	unsigned long flags;
-			
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_blkdev_release\n");
-#endif /* IDETAPE_DEBUG_LOG */
+		/*
+		 *	We have a read-ahead buffer. Scan it for crossed
+		 *	filemarks.
+		 */
+		tape->merge_stage_size = 0;
+		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		while (tape->first_stage != NULL) {
+			/*
+			 *	Wait until the first read-ahead request
+			 *	is serviced.
+			 */
+			save_flags (flags);
+			cli ();
+			if (tape->active_stage == tape->first_stage)
+				idetape_wait_for_request (tape->active_data_request);
+			restore_flags (flags);
 
-	save_flags (flags);cli ();
-	tape->busy=0;
-	restore_flags (flags);
+			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+				count++;
+			if (count == mt_count) {
+				switch (mt_op) {
+					case MTFSF:
+						idetape_remove_stage_head (drive);
+					case MTFSFM:
+						return (0);
+					default:
+						break;
+				}
+			}
+			idetape_remove_stage_head (drive);
+		}
+		idetape_discard_read_pipeline (drive);
+	}
 
-	return;
+	/*
+	 *	The filemark was not found in our internal pipeline.
+	 *	Now we can issue the space command.
+	 */
+	switch (mt_op) {
+		case MTFSF:
+			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);
+			if (retval) return (retval);
+			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+		default:
+			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			return (-EIO);
+	}
 }
 
-/*
- *	Character device interface functions
- */
 
 /*
  *	Our character device read / write functions.
@@ -3667,10 +2936,6 @@
  *	an integral number of the "continuous transfer limit", which is
  *	a parameter of the specific tape (26 KB on my particular tape).
  *
- *	For best results use an integral number of the tape's parameter
- *	(which is displayed in the driver installation stage and is returned
- *	 by the MTIOCGET ioctl).
- *
  *	As of version 1.3 of the driver, the character device provides an
  *	abstract continuous view of the media - any mix of block sizes (even 1
  *	byte) on the same backup/restore procedure is supported. The driver
@@ -3679,226 +2944,150 @@
  *	size will only result in a (slightly) increased driver overhead, but
  *	will no longer hit performance.
  */
-
-int idetape_chrdev_read (struct inode *inode, struct file *file, char *buf, int count)
-
+static long idetape_chrdev_read (struct inode *inode, struct file *file, char *buf, unsigned long count)
 {
-	ide_drive_t *drive=idetape_chrdev.drive;
-	idetape_tape_t *tape=&(drive->tape);
-	char *buf_ptr=buf;
-	int bytes_read,temp,actually_read=0;
+	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	idetape_tape_t *tape = drive->driver_data;
+	int bytes_read,temp,actually_read=0, original_count = count;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_chrdev_read\n");
+	printk (KERN_INFO "Reached idetape_chrdev_read\n");
 #endif /* IDETAPE_DEBUG_LOG */
-
+	
 	if (tape->chrdev_direction != idetape_direction_read) {		/* Initialize read operation */
 		if (tape->chrdev_direction == idetape_direction_write) {
 			idetape_empty_write_pipeline (drive);
 			idetape_flush_tape_buffers (drive);
 		}
-		
+#if IDETAPE_DEBUG_BUGS
+		if (tape->merge_stage || tape->merge_stage_size) {
+			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			tape->merge_stage_size = 0;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		if ((tape->merge_stage = __idetape_kmalloc_stage (tape)) == NULL)
+			return -ENOMEM;
+		tape->chrdev_direction = idetape_direction_read;
+
 		/*
 		 *	Issue a read 0 command to ensure that DSC handshake
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		 
-		bytes_read=idetape_queue_rw_tail (drive,IDETAPE_READ_REQUEST,0,tape->merge_buffer);
-		if (bytes_read < 0)
-			return (bytes_read);
-
-		tape->chrdev_direction=idetape_direction_read;
+		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		if (bytes_read < 0) {
+			kfree (tape->merge_stage);
+			tape->merge_stage = NULL;
+			tape->chrdev_direction = idetape_direction_none;
+			return bytes_read;
+		}
+		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
+			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
+				tape->user_bs_factor = count / tape->tape_block_size;
 	}
-	
 	if (count==0)
 		return (0);
-
-	if (tape->merge_buffer_size) {
-#if IDETAPE_DEBUG_BUGS
-		if (tape->merge_buffer_offset+tape->merge_buffer_size > tape->data_buffer_size) {
-			printk ("ide-tape: bug: merge buffer too big\n");
-			tape->merge_buffer_offset=0;tape->merge_buffer_size=tape->data_buffer_size-1;
-		}
-#endif /* IDETAPE_DEBUG_BUGS */
-		actually_read=IDETAPE_MIN (tape->merge_buffer_size,count);
-		copy_to_user (buf_ptr,tape->merge_buffer+tape->merge_buffer_offset,actually_read);
-		buf_ptr+=actually_read;tape->merge_buffer_size-=actually_read;
-		count-=actually_read;tape->merge_buffer_offset+=actually_read;
+	if (tape->merge_stage_size) {
+		actually_read=IDETAPE_MIN (tape->merge_stage_size,count);
+		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
+		buf += actually_read; tape->merge_stage_size -= actually_read; count-=actually_read;
 	}
-
-	while (count >= tape->data_buffer_size) {
-		bytes_read=idetape_add_chrdev_read_request (drive,tape->capabilities.ctl,tape->merge_buffer);
+	while (count >= tape->stage_size) {
+		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
-			return (actually_read);
-		copy_to_user (buf_ptr,tape->merge_buffer,bytes_read);
-		buf_ptr+=bytes_read;count-=bytes_read;actually_read+=bytes_read;
+			goto finish;
+		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
+		buf += bytes_read; count -= bytes_read; actually_read += bytes_read;
 	}
-
 	if (count) {
-		bytes_read=idetape_add_chrdev_read_request (drive,tape->capabilities.ctl,tape->merge_buffer);
+		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
-			return (actually_read);
+			goto finish;
 		temp=IDETAPE_MIN (count,bytes_read);
-		copy_to_user (buf_ptr,tape->merge_buffer,temp);
+		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
 		actually_read+=temp;
-		tape->merge_buffer_offset=temp;
-		tape->merge_buffer_size=bytes_read-temp;
+		tape->merge_stage_size=bytes_read-temp;
 	}
+finish:
+	if (actually_read < original_count && test_bit (IDETAPE_FILEMARK, &tape->flags))
+		idetape_space_over_filemarks (drive, MTFSF, 1);
 	return (actually_read);
 }
  
-int idetape_chrdev_write (struct inode *inode, struct file *file, const char *buf, int count)
-
+static long idetape_chrdev_write (struct inode *inode, struct file *file, const char *buf, unsigned long count)
 {
-	ide_drive_t *drive=idetape_chrdev.drive;
-	idetape_tape_t *tape=&(drive->tape);
-	const char *buf_ptr=buf;
+	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	idetape_tape_t *tape = drive->driver_data;
 	int retval,actually_written=0;
 
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_chrdev_write\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
-		if (tape->chrdev_direction == idetape_direction_read)
-			idetape_discard_read_pipeline (drive);
-
-		/*
-		 *	Issue a write 0 command to ensure that DSC handshake
-		 *	is switched from completion mode to buffer available
-		 *	mode.
-		 */
-
-		retval=idetape_queue_rw_tail (drive,IDETAPE_WRITE_REQUEST,0,tape->merge_buffer);
-		if (retval < 0)
-			return (retval);		
-
-		tape->chrdev_direction=idetape_direction_write;
-	}
-
-	if (count==0)
-		return (0);
-
-	if (tape->merge_buffer_size) {
-#if IDETAPE_DEBUG_BUGS
-		if (tape->merge_buffer_size >= tape->data_buffer_size) {
-			printk ("ide-tape: bug: merge buffer too big\n");
-			tape->merge_buffer_size=0;
-		}
-#endif /* IDETAPE_DEBUG_BUGS */
-
-		actually_written=IDETAPE_MIN (tape->data_buffer_size-tape->merge_buffer_size,count);
-		copy_from_user (tape->merge_buffer+tape->merge_buffer_size,buf_ptr,actually_written);
-		buf_ptr+=actually_written;tape->merge_buffer_size+=actually_written;count-=actually_written;
-
-		if (tape->merge_buffer_size == tape->data_buffer_size) {
-			tape->merge_buffer_size=0;
-			retval=idetape_add_chrdev_write_request (drive,tape->capabilities.ctl,tape->merge_buffer);
-			if (retval <= 0)
-				return (retval);
-		}
-	}
-
-	while (count >= tape->data_buffer_size) {
-		copy_from_user (tape->merge_buffer,buf_ptr,tape->data_buffer_size);
-		buf_ptr+=tape->data_buffer_size;count-=tape->data_buffer_size;
-		retval=idetape_add_chrdev_write_request (drive,tape->capabilities.ctl,tape->merge_buffer);
-		actually_written+=tape->data_buffer_size;
-		if (retval <= 0)
-			return (retval);
-	}
-
-	if (count) {
-		actually_written+=count;
-		copy_from_user (tape->merge_buffer,buf_ptr,count);
-		tape->merge_buffer_size+=count;
-	}
-	return (actually_written);
-}
-
-/*
- *	Our character device ioctls.
- *
- *	General mtio.h magnetic io commands are supported here, and not in
- *	the corresponding block interface.
- *
- *	The following ioctls are supported:
- *
- *	MTIOCTOP -	Refer to idetape_mtioctop for detailed description.
- *
- *	MTIOCGET - 	The mt_dsreg field in the returned mtget structure
- *			will be set to (recommended block size <<
- *			MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK, which
- *			is currently equal to the size itself.
- *			The other mtget fields are not supported.
- *
- *			Note that we do not actually return the tape's
- *			block size. Rather, we provide the recommended
- *			number of bytes which should be used as a "user
- *			block size" with the character device read/write
- *			functions to maximize throughput.
- *
- *	MTIOCPOS -	The current tape "position" is returned.
- *			(A unique number which can be used with the MTSEEK
- *			 operation to return to this position in some
- *			 future time, provided this place was not overwritten
- *			 meanwhile).
- *
- *	Our own ide-tape ioctls are supported on both interfaces.
- */
-
-int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-
-{
-	ide_drive_t *drive=idetape_chrdev.drive;
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_packet_command_t pc;
-	struct mtop mtop;
-	struct mtget mtget;
-	struct mtpos mtpos;
-	int retval;
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+	printk (KERN_INFO "Reached idetape_chrdev_write\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_flush_tape_buffers (drive);
-	}
+	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
+		if (tape->chrdev_direction == idetape_direction_read)
+			idetape_discard_read_pipeline (drive);
+#if IDETAPE_DEBUG_BUGS
+		if (tape->merge_stage || tape->merge_stage_size) {
+			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			tape->merge_stage_size = 0;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		if ((tape->merge_stage = __idetape_kmalloc_stage (tape)) == NULL)
+			return -ENOMEM;
+		tape->chrdev_direction = idetape_direction_write;
+		idetape_init_merge_stage (tape);
 
-	if (tape->chrdev_direction == idetape_direction_read && cmd != MTIOCTOP)
-		idetape_discard_read_pipeline (drive);
-	
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
+		/*
+		 *	Issue a write 0 command to ensure that DSC handshake
+		 *	is switched from completion mode to buffer available
+		 *	mode.
+		 */
+		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		if (retval < 0) {
+			kfree (tape->merge_stage);
+			tape->merge_stage = NULL;
+			tape->chrdev_direction = idetape_direction_none;
+			return retval;
+		}
+		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
+			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
+				tape->user_bs_factor = count / tape->tape_block_size;
+	}
+	if (count==0)
+		return (0);
+	if (tape->merge_stage_size) {
+#if IDETAPE_DEBUG_BUGS
+		if (tape->merge_stage_size >= tape->stage_size) {
+			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
+			tape->merge_stage_size=0;
+		}
+#endif /* IDETAPE_DEBUG_BUGS */
+		actually_written=IDETAPE_MIN (tape->stage_size-tape->merge_stage_size,count);
+		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
+		buf+=actually_written;tape->merge_stage_size+=actually_written;count-=actually_written;
 
-	switch (cmd) {
-		case MTIOCTOP:
-			retval=verify_area (VERIFY_READ,(char *) arg,sizeof (struct mtop));
-			if (retval) return (retval);
-			copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop));
-			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
-		case MTIOCGET:
-			mtget.mt_dsreg=(tape->data_buffer_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
-			retval=verify_area (VERIFY_WRITE,(char *) arg,sizeof (struct mtget));
-			if (retval) return (retval);
-			copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget));
-			return (0);
-		case MTIOCPOS:
-			idetape_create_read_position_cmd (&pc);
-			retval=idetape_queue_pc_tail (drive,&pc);
-			if (retval) return (retval);
-			mtpos.mt_blkno=tape->block_address;
-			retval=verify_area (VERIFY_WRITE,(char *) arg,sizeof (struct mtpos));
-			if (retval) return (retval);
-			copy_to_user ((char *) arg,(char *) &mtpos, sizeof (struct mtpos));
-			return (0);
-		default:
-			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
+		if (tape->merge_stage_size == tape->stage_size) {
+			tape->merge_stage_size = 0;
+			retval=idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			if (retval <= 0)
+				return (retval);
+		}
+	}
+	while (count >= tape->stage_size) {
+		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
+		buf+=tape->stage_size;count-=tape->stage_size;
+		retval=idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		actually_written+=tape->stage_size;
+		if (retval <= 0)
+			return (retval);
+	}
+	if (count) {
+		actually_written+=count;
+		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
+		tape->merge_stage_size+=count;
 	}
+	return (actually_written);
 }
 
 /*
@@ -3918,7 +3107,6 @@
  *
  *	MTBSFM	-	Like MTBSF, only tape is positioned after the last filemark.
  *
- *
  *	Note:
  *
  *		MTBSF and MTBSFM are not supported when the tape doesn't
@@ -3932,8 +3120,10 @@
  *
  *	MTREW	-	Rewinds tape.
  *
+ *	MTLOAD	-	Loads the tape.
+ *
  *	MTOFFL	-	Puts the tape drive "Offline": Rewinds the tape and
- *			prevents further access until the media is replaced.
+ *	MTUNLOAD	prevents further access until the media is replaced.
  *
  *	MTNOP	-	Flushes tape buffers.
  *
@@ -3944,35 +3134,33 @@
  *
  *	MTERASE	-	Erases tape.
  *
- *	MTSEEK	-	Positions the tape in a specific block number, which
- *			was previously received using the MTIOCPOS ioctl,
- *			assuming this place was not overwritten meanwhile.
+ *	MTSETBLK - 	Sets the user block size to mt_count bytes. If
+ *			mt_count is 0, we will attempt to autodetect
+ *			the block size.
+ *
+ *	MTSEEK	-	Positions the tape in a specific block number, where
+ *			each block is assumed to contain which user_block_size
+ *			bytes.
+ *
+ *	MTSETPART - 	Switches to another tape partition.
  *
  *	The following commands are currently not supported:
  *
- *	MTFSR, MTBSR, MTFSS, MTBSS, MTWSM, MTSETBLK, MTSETDENSITY,
+ *	MTFSR, MTBSR, MTFSS, MTBSS, MTWSM, MTSETDENSITY,
  *	MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD.
  */
- 
-int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
-
+static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_packet_command_t pc;
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t pc;
 	int i,retval;
 
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
-
 #if IDETAPE_DEBUG_LOG
-	printk ("Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+	printk (KERN_INFO "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
 #endif /* IDETAPE_DEBUG_LOG */
-
 	/*
 	 *	Commands which need our pipelined read-ahead stages.
 	 */
-
 	switch (mt_op) {
 		case MTFSF:
 		case MTFSFM:
@@ -3988,7 +3176,6 @@
 	/*
 	 *	Empty the pipeline.
 	 */
-
 	if (tape->chrdev_direction == idetape_direction_read)
 		idetape_discard_read_pipeline (drive);
 
@@ -4002,6 +3189,10 @@
 			return (0);
 		case MTREW:
 			return (idetape_rewind_tape (drive));
+		case MTLOAD:
+			idetape_create_load_unload_cmd (&pc, IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail (drive,&pc));
+		case MTUNLOAD:
 		case MTOFFL:
 			idetape_create_load_unload_cmd (&pc,!IDETAPE_LU_LOAD_MASK);
 			return (idetape_queue_pc_tail (drive,&pc));
@@ -4014,607 +3205,582 @@
 			idetape_create_space_cmd (&pc,0,IDETAPE_SPACE_TO_EOD);
 			return (idetape_queue_pc_tail (drive,&pc));
 		case MTERASE:
-			retval=idetape_rewind_tape (drive);
-			if (retval) return (retval);
+			(void) idetape_rewind_tape (drive);
 			idetape_create_erase_cmd (&pc);
 			return (idetape_queue_pc_tail (drive,&pc));
+		case MTSETBLK:
+			if (mt_count) {
+				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
+					return -EIO;
+				tape->user_bs_factor = mt_count / tape->tape_block_size;
+				clear_bit (IDETAPE_DETECT_BS, &tape->flags);
+			} else
+				set_bit (IDETAPE_DETECT_BS, &tape->flags);
+			return 0;
 		case MTSEEK:
-			return (idetape_position_tape (drive,mt_count));
+			return (idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition));
+		case MTSETPART:
+			return (idetape_position_tape (drive, 0, mt_count));
 		default:
-			printk ("ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
 	}
 }
 
 /*
- *	idetape_space_over_filemarks is now a bit more complicated than just
- *	passing the command to the tape since we may have crossed some
- *	filemarks during our pipelined read-ahead mode.
+ *	Our character device ioctls.
  *
- *	As a minor side effect, the pipeline enables us to support MTFSFM when
- *	the filemark is in our internal pipeline even if the tape doesn't
- *	support spacing over filemarks in the reverse direction.
- */
- 
-int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
-
-{
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_packet_command_t pc;
-	unsigned long flags;
-	int retval,count=0,errors;
-
-	if (tape->chrdev_direction == idetape_direction_read) {
-
-		/*
-		 *	We have a read-ahead buffer. Scan it for crossed
-		 *	filemarks.
-		 */
-
-		tape->merge_buffer_size=tape->merge_buffer_offset=0;
-		while (tape->first_stage != NULL) {
-			
-			/*
-			 *	Wait until the first read-ahead request
-			 *	is serviced.
-			 */
-		
-			save_flags (flags);cli ();
-			if (tape->active_data_request == &(tape->first_stage->rq))
-				idetape_wait_for_request (tape->active_data_request);
-			restore_flags (flags);
-
-			errors=tape->first_stage->rq.errors;
-			if (errors == IDETAPE_RQ_ERROR_FILEMARK)
-				count++;
-
-			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						idetape_remove_stage_head (drive);
-					case MTFSFM:
-						return (0);
-				}
-			}
-			idetape_remove_stage_head (drive);
-		}
-		idetape_discard_read_pipeline (drive);
-	}
-
-	/*
-	 *	The filemark was not found in our internal pipeline.
-	 *	Now we can issue the space command.
-	 */
-
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
-
-	switch (mt_op) {
-		case MTFSF:
-			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_mtioctop (drive,MTFSF,mt_count-count);
-			if (retval) return (retval);
-			return (idetape_mtioctop (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_mtioctop (drive,MTBSF,mt_count+count);
-			if (retval) return (retval);
-			return (idetape_mtioctop (drive,MTFSF,1));
-		default:
-			printk ("ide-tape: MTIO operation %d not supported\n",mt_op);
-			return (-EIO);
-	}
-}
-
-/*
- *	Our character device open function.
- */
-
-int idetape_chrdev_open (struct inode *inode, struct file *filp)
-
-{
-	ide_drive_t *drive=idetape_chrdev.drive;
-	idetape_tape_t *tape=&(drive->tape);
-	unsigned long flags;
-	unsigned int minor=MINOR (inode->i_rdev),allocation_length;
-			
-	save_flags (flags);cli ();
-
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_chrdev_open\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-	if (minor!=0 && minor!=128) {		/* Currently supporting only one */
-		restore_flags (flags);		/* tape drive */
-		return (-ENXIO);
-	}
-
-	if (tape->busy) {
-		restore_flags (flags);		/* Allowing access only through one */
-		return (-EBUSY);		/* one file descriptor */
-	}
-
-	tape->busy=1;
-	restore_flags (flags);
-
-	allocation_length=tape->data_buffer_size;
-	if (tape->data_buffer_size % IDETAPE_ALLOCATION_BLOCK)
-		allocation_length+=IDETAPE_ALLOCATION_BLOCK;
-
-#if IDETAPE_MINIMIZE_IDLE_MEMORY_USAGE
-	if (tape->data_buffer == NULL)
-		tape->data_buffer=kmalloc (allocation_length,GFP_KERNEL);
-	if (tape->data_buffer == NULL)
-		goto sorry;
-	if (tape->merge_buffer == NULL)
-		tape->merge_buffer=kmalloc (allocation_length,GFP_KERNEL);
-	if (tape->merge_buffer == NULL) {
-		kfree (tape->data_buffer);
-	sorry:
-		printk ("ide-tape: FATAL - Can not allocate continuous buffer of %d bytes\n",allocation_length);
-		tape->busy=0;
-		return (-EIO);
-	}
-#endif /* IDETAPE_MINIMIZE_IDLE_MEMORY_USAGE */
-
-	if (!tape->block_address_valid) {
-		if (idetape_rewind_tape (drive)) {
-			printk ("ide-tape: Rewinding tape failed\n");
-			tape->busy=0;
-			return (-EIO);
-		}
-	}
-
-	return (0);
-}
-
-/*
- *	Our character device release function.
- */
-
-void idetape_chrdev_release (struct inode *inode, struct file *filp)
-
-{
-	ide_drive_t *drive=idetape_chrdev.drive;
-	idetape_tape_t *tape=&(drive->tape);
-	unsigned int minor=MINOR (inode->i_rdev);
-	idetape_packet_command_t pc;
-	unsigned long flags;
-			
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_chrdev_release\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_create_write_filemark_cmd (&pc,1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive,&pc))
-			printk ("ide-tape: Couldn't write a filemark\n");
-	}
-	
-	if (tape->chrdev_direction == idetape_direction_read) {
-		if (minor < 128)
-			idetape_discard_read_pipeline (drive);
-		else
-			idetape_wait_for_pipeline (drive);
-	}
-	
-	if (minor < 128)
-		if (idetape_rewind_tape (drive))
-			printk ("ide-tape: Rewinding tape failed\n");
-
-#if IDETAPE_MINIMIZE_IDLE_MEMORY_USAGE
-	kfree (tape->data_buffer);
-	tape->data_buffer=NULL;
-	if (!tape->merge_buffer_size) {
-		kfree (tape->merge_buffer);
-		tape->merge_buffer=NULL;
-	}
-#endif /* IDETAPE_MINIMIZE_IDLE_MEMORY_USAGE */
-
-	save_flags (flags);cli ();
-	tape->busy=0;
-	restore_flags (flags);
-
-	return;
-}
-
-/*
- *	idetape_position_tape positions the tape to the requested block
- *	using the LOCATE packet command. A READ POSITION command is then
- *	issued to check where we are positioned.
+ *	General mtio.h magnetic io commands are supported here, and not in
+ *	the corresponding block interface.
  *
- *	Like all higher level operations, we queue the commands at the tail
- *	of the request queue and wait for their completion.
- *	
- */
- 
-int idetape_position_tape (ide_drive_t *drive,unsigned long block)
-
-{
-	int retval;
-	idetape_packet_command_t pc;
-
-	idetape_create_locate_cmd (&pc,block,0);
-	retval=idetape_queue_pc_tail (drive,&pc);
-	if (retval!=0) return (retval);
-			
-	idetape_create_read_position_cmd (&pc);
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
-	return (idetape_queue_pc_tail (drive,&pc));
-}
-
-/*
- *	Rewinds the tape to the Beginning Of the current Partition (BOP).
+ *	The following ioctls are supported:
  *
- *	We currently support only one partition.
- */ 
-
-int idetape_rewind_tape (ide_drive_t *drive)
-
-{
-	int retval;
-	idetape_packet_command_t pc;
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_rewind_tape\n");
-#endif /* IDETAPE_DEBUG_LOG */	
-	
-	idetape_create_rewind_cmd (&pc);
-	retval=idetape_queue_pc_tail (drive,&pc);
-	if (retval) return (retval);
-			
-	idetape_create_read_position_cmd (&pc);
-	pc.buffer=pc.temp_buffer;
-	pc.buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
-	pc.current_position=pc.temp_buffer;
-	return (idetape_queue_pc_tail (drive,&pc));
-}
-
-int idetape_flush_tape_buffers (ide_drive_t *drive)
-
-{
-	idetape_packet_command_t pc;
-
-	idetape_create_write_filemark_cmd (&pc,0);
-	return (idetape_queue_pc_tail (drive,&pc));
-}
-
-/*
- *	Pipeline related functions
- */
-
-/*
- *	idetape_kmalloc_stage uses kmalloc to allocate a pipeline stage,
- *	along with all the necessary small buffers which together make
- *	a buffer of size tape->data_buffer_size or a bit more, in case
- *	it is not a multiply of IDETAPE_ALLOCATION_BLOCK (it isn't ...).
+ *	MTIOCTOP -	Refer to idetape_mtioctop for detailed description.
  *
- *	Returns a pointer to the new allocated stage, or NULL if we
- *	can't (or don't want to, in case we already have too many stages)
- *	allocate a stage.
+ *	MTIOCGET - 	The mt_dsreg field in the returned mtget structure
+ *			will be set to (user block size in bytes <<
+ *			MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK.
  *
- *	Pipeline stages are optional and are used to increase performance.
- *	If we can't allocate them, we'll manage without them.
+ *			The mt_blkno is set to the current user block number.
+ *			The other mtget fields are not supported.
+ *
+ *	MTIOCPOS -	The current tape "block position" is returned. We
+ *			assume that each block contains user_block_size
+ *			bytes.
+ *
+ *	Our own ide-tape ioctls are supported on both interfaces.
  */
- 
-idetape_pipeline_stage_t *idetape_kmalloc_stage (ide_drive_t *drive)
-
+static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_pipeline_stage_t *new_stage;
-	idetape_buffer_head_t *prev_bh,*bh;
-	int buffers_num,i;
-	
+	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t pc;
+	struct mtop mtop;
+	struct mtget mtget;
+	struct mtpos mtpos;
+	int retval, block_offset = 0;
+
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_kmalloc_stage\n");
+	printk (KERN_INFO "Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->current_number_of_stages>=tape->max_number_of_stages) {
-		return (NULL);
+	if (tape->chrdev_direction == idetape_direction_write) {
+		idetape_empty_write_pipeline (drive);
+		idetape_flush_tape_buffers (drive);
 	}
-		
-	new_stage=(idetape_pipeline_stage_t *) kmalloc (sizeof (idetape_pipeline_stage_t),GFP_KERNEL);
-	if (new_stage==NULL)
-		return (NULL);
-		
-	new_stage->next=new_stage->prev=NULL;
-
-	buffers_num=tape->data_buffer_size / IDETAPE_ALLOCATION_BLOCK;
-	if (tape->data_buffer_size % IDETAPE_ALLOCATION_BLOCK)
-		buffers_num++;
-
-	prev_bh=new_stage->bh=(idetape_buffer_head_t *) kmalloc (sizeof (idetape_buffer_head_t),GFP_KERNEL);
-	if (new_stage->bh==NULL) {
-		idetape_kfree_stage (new_stage);
-		return (NULL);
-	}
-	new_stage->bh->next=NULL;
-
-	new_stage->bh->data=kmalloc (IDETAPE_ALLOCATION_BLOCK,GFP_KERNEL);
-	if (new_stage->bh->data==NULL) {
-		idetape_kfree_stage (new_stage);
-		return (NULL);
+	if (cmd == MTIOCGET || cmd == MTIOCPOS) {
+		block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
+		idetape_create_read_position_cmd (&pc);
+		retval=idetape_queue_pc_tail (drive,&pc);
+		if (retval) return (retval);
 	}
-	
-	for (i=1;i<buffers_num;i++) {
-		bh=(idetape_buffer_head_t *) kmalloc (sizeof (idetape_buffer_head_t),GFP_KERNEL);
-		if (bh==NULL) {
-			idetape_kfree_stage (new_stage);
-			return (NULL);
-		}
-		bh->next=NULL;
-		prev_bh->next=bh;
-		bh->data=kmalloc (IDETAPE_ALLOCATION_BLOCK,GFP_KERNEL);
-		if (bh->data == NULL) {
-			idetape_kfree_stage (new_stage);
-			return (NULL);
-		}
-		prev_bh=bh;
+	switch (cmd) {
+		case MTIOCTOP:
+			if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+				return -EFAULT;
+			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
+		case MTIOCGET:
+			memset (&mtget, 0, sizeof (struct mtget));
+			mtget.mt_blkno = tape->block_address / tape->user_bs_factor - block_offset;
+			mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
+			if (copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget)))
+				return -EFAULT;
+			return 0;
+		case MTIOCPOS:
+			mtpos.mt_blkno = tape->block_address / tape->user_bs_factor - block_offset;
+			if (copy_to_user ((char *) arg,(char *) &mtpos, sizeof (struct mtpos)))
+				return -EFAULT;
+			return 0;
+		default:
+			if (tape->chrdev_direction == idetape_direction_read)
+				idetape_discard_read_pipeline (drive);
+			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
 	}
-	return (new_stage);
 }
 
 /*
- *	idetape_kfree_stage calls kfree to completely free a stage, along with
- *	its related buffers.
+ *	Our character device open function.
  */
- 
-void idetape_kfree_stage (idetape_pipeline_stage_t *stage)
-
+static int idetape_chrdev_open (struct inode *inode, struct file *filp)
 {
-	idetape_buffer_head_t *prev_bh,*bh;
-	
-	if (stage == NULL)
-		return;
-
+	ide_drive_t *drive;
+	idetape_tape_t *tape;
+	idetape_pc_t pc;
+			
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_kfree_stage\n");
+	printk (KERN_INFO "Reached idetape_chrdev_open\n");
 #endif /* IDETAPE_DEBUG_LOG */
 	
-	bh=stage->bh;
-	
-	while (bh != NULL) {
-		prev_bh=bh;
-		if (bh->data != NULL)
-			kfree (bh->data);
-		bh=bh->next;
-		kfree (prev_bh);
-	}
-	
-	kfree (stage);
-	return;
+	if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
+		return -ENXIO;
+	tape = drive->driver_data;
+
+	if (set_bit (IDETAPE_BUSY, &tape->flags))
+		return -EBUSY;
+	MOD_INC_USE_COUNT;
+	idetape_create_read_position_cmd (&pc);
+	(void) idetape_queue_pc_tail (drive,&pc);
+	if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
+		(void) idetape_rewind_tape (drive);
+	MOD_DEC_USE_COUNT;
+
+	if (tape->chrdev_direction == idetape_direction_none)
+		MOD_INC_USE_COUNT;
+	return 0;
 }
 
 /*
- *	idetape_copy_buffer_from_stage and idetape_copy_buffer_to_stage
- *	copy data from/to the small buffers into/from a continuous buffer.
+ *	Our character device release function.
  */
-  
-void idetape_copy_buffer_from_stage (idetape_pipeline_stage_t *stage,char *buffer)
-
+static void idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	idetape_buffer_head_t *bh;
-	char *ptr;
-
+	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	idetape_tape_t *tape = drive->driver_data;
+	unsigned int minor=MINOR (inode->i_rdev);
+	idetape_pc_t pc;
+			
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_copy_buffer_from_stage\n");
+	printk (KERN_INFO "Reached idetape_chrdev_release\n");
 #endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
-	if (buffer == NULL) {
-		printk ("ide-tape: bug: buffer is null in copy_buffer_from_stage\n");
-		return;
-	}
-#endif /* IDETAPE_DEBUG_BUGS */
-	
-	ptr=buffer;
-	bh=stage->bh;
-	
-	while (bh != NULL) {
-#if IDETAPE_DEBUG_BUGS
-		if (bh->data == NULL) {
-			printk ("ide-tape: bug: bh->data is null\n");
-			return;
+
+	if (tape->chrdev_direction == idetape_direction_write) {
+		idetape_empty_write_pipeline (drive);
+		tape->merge_stage = __idetape_kmalloc_stage (tape);
+		if (tape->merge_stage != NULL) {
+			idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+			__idetape_kfree_stage (tape->merge_stage);
+			tape->merge_stage = NULL;
 		}
-#endif /* IDETAPE_DEBUG_BUGS */
-		memcpy (ptr,bh->data,IDETAPE_ALLOCATION_BLOCK);
-		bh=bh->next;
-		ptr=ptr+IDETAPE_ALLOCATION_BLOCK;
+		idetape_create_write_filemark_cmd (&pc,1);	/* Write a filemark */
+		if (idetape_queue_pc_tail (drive,&pc))
+			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
+	}
+	if (tape->chrdev_direction == idetape_direction_read) {
+		if (minor < 128)
+			idetape_discard_read_pipeline (drive);
+		else
+			idetape_wait_for_pipeline (drive);
 	}
-	return;
+	if (tape->cache_stage != NULL) {
+		__idetape_kfree_stage (tape->cache_stage);
+		tape->cache_stage = NULL;
+	}
+	if (minor < 128)
+		(void) idetape_rewind_tape (drive);
+
+	clear_bit (IDETAPE_BUSY, &tape->flags);
+	if (tape->chrdev_direction == idetape_direction_none)
+		MOD_DEC_USE_COUNT;
 }
 
 /*
- *	Here we copy a continuous data buffer to the various small buffers
- *	in the pipeline stage.
+ *	idetape_identify_device is called to check the contents of the
+ *	ATAPI IDENTIFY command results. We return:
+ *
+ *	1	If the tape can be supported by us, based on the information
+ *		we have so far.
+ *
+ *	0 	If this tape driver is not currently supported by us.
  */
- 
-void idetape_copy_buffer_to_stage (idetape_pipeline_stage_t *stage,char *buffer)
-
+static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
 {
-	idetape_buffer_head_t *bh;
-	char *ptr;
-
+	struct idetape_id_gcw gcw;
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_copy_buffer_to_stage\n");
+	unsigned short mask,i;
 #endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
-	if (buffer == NULL) {
-		printk ("ide-tape: bug: buffer is null in copy_buffer_to_stage\n");
-		return;
-	}
-#endif /* IDETAPE_DEBUG_BUGS */
-
-	ptr=buffer;
-	bh=stage->bh;
-	
-	while (bh != NULL) {
-#if IDETAPE_DEBUG_BUGS
-		if (bh->data == NULL) {
-			printk ("ide-tape: bug: bh->data is null\n");
-			return;
-		}
-#endif /* IDETAPE_DEBUG_BUGS */
-		memcpy (bh->data,ptr,IDETAPE_ALLOCATION_BLOCK);
-		bh=bh->next;
-		ptr=ptr+IDETAPE_ALLOCATION_BLOCK;
-	}
-	return;
-}
-
-/*
- *	idetape_increase_max_pipeline_stages is a part of the feedback
- *	loop which tries to find the optimum number of stages. In the
- *	feedback loop, we are starting from a minimum maximum number of
- *	stages, and if we sense that the pipeline is empty, we try to
- *	increase it, until we reach the user compile time memory limit.
- */
 
-void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
+	*((unsigned short *) &gcw) = id->config;
 
-{
-	idetape_tape_t *tape=&(drive->tape);
-	
 #if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_increase_max_pipeline_stages\n");
-#endif /* IDETAPE_DEBUG_LOG */
+	printk (KERN_INFO "Dumping ATAPI Identify Device tape parameters\n");
+	printk (KERN_INFO "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;
+	}
+	printk (KERN_INFO "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");
+	}
+	printk (KERN_INFO "Removable: %s",gcw.removable ? "Yes\n":"No\n");	
+	printk (KERN_INFO "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;
+	}
+	printk (KERN_INFO "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;
+	}
+	printk (KERN_INFO "Model: %s\n",id->model);
+	printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
+	printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+	printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512);
+	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk (KERN_INFO "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);
+		if (id->dma_1word & (mask << 8))
+			printk (KERN_INFO "(active) ");
+	}
+	printk (KERN_INFO "\n");
+	printk (KERN_INFO "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);
+		if (id->dma_mword & (mask << 8))
+			printk (KERN_INFO "(active) ");
+	}
+	printk (KERN_INFO "\n");
+	if (id->field_valid & 0x0002) {
+		printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk (KERN_INFO "Minimum Multi-word DMA cycle per word: ");
+		if (id->eide_dma_min == 0)
+			printk (KERN_INFO "Not supported\n");
+		else
+			printk (KERN_INFO "%d ns\n",id->eide_dma_min);
 
-	tape->max_number_of_stages+=IDETAPE_INCREASE_STAGES_RATE;
+		printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: ");
+		if (id->eide_dma_time == 0)
+			printk (KERN_INFO "Not supported\n");
+		else
+			printk (KERN_INFO "%d ns\n",id->eide_dma_time);
 
-	if (tape->max_number_of_stages >= IDETAPE_MAX_PIPELINE_STAGES)
-		tape->max_number_of_stages = IDETAPE_MAX_PIPELINE_STAGES;
+		printk (KERN_INFO "Minimum PIO cycle without IORDY: ");
+		if (id->eide_pio == 0)
+			printk (KERN_INFO "Not supported\n");
+		else
+			printk (KERN_INFO "%d ns\n",id->eide_pio);
 
-#if IDETAPE_DEBUG_LOG
-	printk ("Maximum number of stages: %d\n",tape->max_number_of_stages);
+		printk (KERN_INFO "Minimum PIO cycle with IORDY: ");
+		if (id->eide_pio_iordy == 0)
+			printk (KERN_INFO "Not supported\n");
+		else
+			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+		
+	} else
+		printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	return;
+	/* Check that we can support this device */
+
+	if (gcw.protocol !=2 )
+		printk (KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+	else if (gcw.device_type != 1)
+		printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
+	else if (!gcw.removable)
+		printk (KERN_ERR "ide-tape: The removable flag is not set\n");
+	else if (gcw.drq_type != 2) {
+		printk (KERN_ERR "ide-tape: Sorry, DRQ types other than Accelerated DRQ\n");
+		printk (KERN_ERR "ide-tape: are still not supported by the driver\n");
+	} else if (gcw.packet_size != 0) {
+		printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+		if (gcw.packet_size == 1)
+			printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+	} else
+		return 1;
+	return 0;
 }
 
 /*
- *	idetape_add_stage_tail adds a new stage at the end of the pipeline.
- *
- *	Caller should disable interrupts, if necessary.
+ *	idetape_get_mode_sense_results asks the tape about its various
+ *	parameters. In particular, we will adjust our data transfer buffer
+ *	size to the recommended value as returned by the tape.
  */
- 
-void idetape_add_stage_tail (ide_drive_t *drive,idetape_pipeline_stage_t *stage)
-
+static void idetape_get_mode_sense_results (ide_drive_t *drive)
 {
-	idetape_tape_t *tape=&(drive->tape);
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t pc;
+	idetape_mode_parameter_header_t *header;
+	idetape_capabilities_page_t *capabilities;
 	
-#if IDETAPE_DEBUG_LOG
-		printk ("Reached idetape_add_stage_tail\n");
+	idetape_create_mode_sense_cmd (&pc,IDETAPE_CAPABILITIES_PAGE);
+	if (idetape_queue_pc_tail (drive,&pc)) {
+		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
+		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
+		return;
+	}
+	header = (idetape_mode_parameter_header_t *) pc.buffer;
+	capabilities = (idetape_capabilities_page_t *) (header + 1);
+
+	capabilities->max_speed = ntohs (capabilities->max_speed);
+	capabilities->ctl = ntohs (capabilities->ctl);
+	capabilities->speed = ntohs (capabilities->speed);
+	capabilities->buffer_size = ntohs (capabilities->buffer_size);
+
+	tape->capabilities = *capabilities;		/* Save us a copy */
+	tape->tape_block_size = capabilities->blk512 ? 512:1024;
+#if IDETAPE_DEBUG_LOG
+	printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n");
+	printk (KERN_INFO "Mode Parameter Header:\n");
+	printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length);
+	printk (KERN_INFO "Medium Type - %d\n",header->medium_type);
+	printk (KERN_INFO "Device Specific Parameter - %d\n",header->dsp);
+	printk (KERN_INFO "Block Descriptor Length - %d\n",header->bdl);
+	
+	printk (KERN_INFO "Capabilities and Mechanical Status Page:\n");
+	printk (KERN_INFO "Page code - %d\n",capabilities->page_code);
+	printk (KERN_INFO "Page length - %d\n",capabilities->page_length);
+	printk (KERN_INFO "Read only - %s\n",capabilities->ro ? "Yes":"No");
+	printk (KERN_INFO "Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+	printk (KERN_INFO "Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+	printk (KERN_INFO "Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+	printk (KERN_INFO "Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+	printk (KERN_INFO "The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+	printk (KERN_INFO "The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+	printk (KERN_INFO "Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+	printk (KERN_INFO "Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+	printk (KERN_INFO "Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+	printk (KERN_INFO "Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+	printk (KERN_INFO "Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+	printk (KERN_INFO "Restricted byte count for PIO transfers - %s\n",capabilities->slowb ? "Yes":"No");
+	printk (KERN_INFO "Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+	printk (KERN_INFO "Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+	printk (KERN_INFO "Current speed in KBps - %d\n",capabilities->speed);	
+	printk (KERN_INFO "Buffer size - %d\n",capabilities->buffer_size*512);
 #endif /* IDETAPE_DEBUG_LOG */
-
-	stage->next=NULL;
-	stage->prev=tape->last_stage;
-	if (tape->last_stage != NULL)
-		tape->last_stage->next=stage;
-	else
-		tape->first_stage=tape->next_stage=stage;
-	tape->last_stage=stage;
-	if (tape->next_stage == NULL)
-		tape->next_stage=tape->last_stage;
-	tape->current_number_of_stages++;
 }
 
 /*
- *	idetape_remove_stage_head removes tape->first_stage from the pipeline.
+ *	ide_setup is called to:
+ *
+ *		1.	Initialize our various state variables.
+ *		2.	Ask the tape for its capabilities.
+ *		3.	Allocate a buffer which will be used for data
+ *			transfer. The buffer size is chosen based on
+ *			the recommendation which we received in step (2).
  *
- *	Again, caller should avoid race conditions.
+ *	Note that at this point ide.c already assigned us an irq, so that
+ *	we can queue requests here and wait for their completion.
  */
- 
-void idetape_remove_stage_head (ide_drive_t *drive)
-
+static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_pipeline_stage_t *stage;
-	
-#if IDETAPE_DEBUG_LOG
-		printk ("Reached idetape_remove_stage_head\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage == NULL) {
-		printk ("ide-tape: bug: tape->first_stage is NULL\n");
-		return;		
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long t1, tmid, tn, t;
+
+	drive->driver_data = tape;
+	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
+	memset (tape, 0, sizeof (idetape_tape_t));
+	tape->drive = drive;
+	tape->minor = minor;
+	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
+	tape->chrdev_direction = idetape_direction_none;
+	tape->pc = tape->pc_stack;
+	tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES;
+
+	idetape_get_mode_sense_results (drive);
+
+	tape->user_bs_factor = 1;
+	tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+	while (tape->stage_size > 0xffff) {
+		printk (KERN_NOTICE "ide-tape: decreasing stage size\n");
+		tape->capabilities.ctl /= 2;
+		tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
 	}
-	if (tape->active_stage == tape->first_stage) {
-		printk ("ide-tape: bug: Trying to free our active pipeline stage\n");
-		return;
+	tape->pages_per_stage = tape->stage_size / PAGE_SIZE;
+	if (tape->stage_size % PAGE_SIZE) {
+		tape->pages_per_stage++;
+		tape->excess_bh_size = PAGE_SIZE - tape->stage_size % PAGE_SIZE;
 	}
-#endif /* IDETAPE_DEBUG_BUGS */
-	stage=tape->first_stage;
-	tape->first_stage=stage->next;
-	idetape_kfree_stage (stage);
-	tape->current_number_of_stages--;
-	if (tape->first_stage == NULL) {
-		tape->last_stage=NULL;
-#if IDETAPE_DEBUG_BUGS
-		if (tape->next_stage != NULL)
-			printk ("ide-tape: bug: tape->next_stage != NULL\n");
-		if (tape->current_number_of_stages)
-			printk ("ide-tape: bug: current_number_of_stages should be 0 now\n");
-#endif /* IDETAPE_DEBUG_BUGS */
+
+	/*
+	 *	Select the "best" DSC read/write polling frequency.
+	 *	The following algorithm attempts to find a balance between
+	 *	good latency and good system throughput. It will be nice to
+	 *	have all this configurable in run time at some point.
+	 */
+	t1 = (tape->stage_size * HZ) / (tape->capabilities.speed * 1000);
+	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125);
+	tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (tape->capabilities.speed * 1000);
+
+	if (tape->max_stages) {
+		if (drive->using_dma)
+			t = tmid;
+		else {
+			if (hwif->drives[drive->select.b.unit ^ 1].present || hwif->next != hwif)
+				t = (tn + tmid) / 2;
+			else
+				t = tn;
+		}
+	} else
+		t = t1;
+	t = IDETAPE_MIN (t, tmid);
+
+	/*
+	 *	Ensure that the number we got makes sense.
+	 */
+	tape->best_dsc_rw_frequency = IDETAPE_MAX (IDETAPE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+	if (tape->best_dsc_rw_frequency != t) {
+		printk (KERN_NOTICE "ide-tape: Although the recommended polling period is %lu jiffies\n", t);
+		printk (KERN_NOTICE "ide-tape: we will use %lu jiffies\n", tape->best_dsc_rw_frequency);
 	}
+	printk (KERN_INFO "ide-tape: %s <-> %s, %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
+		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
+		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
 }
 
+static int idetape_cleanup (ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	int minor = tape->minor;
+	unsigned long flags;
+
+	save_flags (flags);
+	cli ();
+	if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
+		restore_flags(flags);
+		return 1;
+	}
+	idetape_chrdevs[minor].drive = NULL;
+	restore_flags (flags);
+	DRIVER(drive)->busy = 0;
+	(void) ide_unregister_subdriver (drive);
+	drive->driver_data = NULL;
+	kfree (tape);
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
+		if (idetape_chrdevs[minor].drive != NULL)
+			return 0;
+	unregister_chrdev (IDETAPE_MAJOR, "ht");
+	idetape_chrdev_present = 0;
+	return 0;
+}
+
+int idetape_init (void);
+
+static ide_module_t idetape_module = {
+	IDE_DRIVER_MODULE,
+	idetape_init,
+	NULL
+};
+
 /*
- *	idetape_insert_pipeline_into_queue is used to start servicing the
- *	pipeline stages, starting from tape->next_stage.
+ *	IDE subdriver functions, registered with ide.c
  */
- 
-void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+static ide_driver_t idetape_driver = {
+	ide_tape,		/* media */
+	1,			/* busy */
+	1,			/* supports_dma */
+	idetape_cleanup,	/* cleanup */
+	idetape_do_request,	/* do_request */
+	idetape_end_request,	/* end_request */
+	idetape_blkdev_ioctl,	/* ioctl */
+	idetape_blkdev_open,	/* open */
+	idetape_blkdev_release,	/* release */
+	NULL,			/* media_change */
+	idetape_pre_reset,	/* pre_reset */
+	NULL,			/* capacity */
+	NULL			/* special */
+};
 
-{
-	idetape_tape_t *tape=&(drive->tape);
+/*
+ *	Our character device supporting functions, passed to register_chrdev.
+ */
+static struct file_operations idetape_fops = {
+	NULL,			/* lseek - default */
+	idetape_chrdev_read,	/* read  */
+	idetape_chrdev_write,	/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	idetape_chrdev_ioctl,	/* ioctl */
+	NULL,			/* mmap */
+	idetape_chrdev_open,	/* open */
+	idetape_chrdev_release,	/* release */
+	NULL,			/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL			/* revalidate */
+};
 
-	if (tape->next_stage == NULL)
-		return;
+/*
+ *	idetape_init will register the driver for each tape.
+ */
+int idetape_init (void)
+{
+	ide_drive_t *drive;
+	idetape_tape_t *tape;
+	int minor, failed = 0, supported = 0;
 
-	if (tape->active_data_request == NULL) {
-		idetape_active_next_stage (drive);
-		(void) (ide_do_drive_cmd (drive,tape->active_data_request,ide_end));
-		return;
-	}
+	MOD_INC_USE_COUNT;
+	if (!idetape_chrdev_present)
+		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+			idetape_chrdevs[minor].drive = NULL;
+
+	if ((drive = ide_scan_devices (ide_tape, NULL, failed++)) == NULL) {
+		ide_register_module (&idetape_module);
+		MOD_DEC_USE_COUNT;
+		return 0;
+	}
+	if (!idetape_chrdev_present && register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
+	do {
+		if (!idetape_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+			continue;
+		}
+		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+		if (tape == NULL) {
+			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (tape);
+			continue;
+		}
+		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+		idetape_setup (drive, tape, minor);
+		idetape_chrdevs[minor].drive = drive;
+		supported++; failed--;
+	} while ((drive = ide_scan_devices (ide_tape, NULL, failed++)) != NULL);
+	if (!idetape_chrdev_present && !supported) {
+		unregister_chrdev (IDETAPE_MAJOR, "ht");
+	} else
+		idetape_chrdev_present = 1;
+	ide_register_module (&idetape_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
-/*
- *	idetape_active_next_stage will declare the next stage as "active".
- */
- 
-void idetape_active_next_stage (ide_drive_t *drive)
+#ifdef MODULE
+int init_module (void)
+{
+	return idetape_init ();
+}
 
+void cleanup_module (void)
 {
-	idetape_tape_t *tape=&(drive->tape);
-	idetape_pipeline_stage_t *stage=tape->next_stage;
-	struct request *rq=&(stage->rq);
+	ide_drive_t *drive;
+	int minor;
 
-#if IDETAPE_DEBUG_LOG
-	printk ("Reached idetape_active_next_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
-	if (stage == NULL) {
-		printk ("ide-tape: bug: Trying to activate a non existing stage\n");
-		return;
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
+		drive = idetape_chrdevs[minor].drive;
+		if (drive != NULL && idetape_cleanup (drive))
+			printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
 	}
-#endif /* IDETAPE_DEBUG_BUGS */	
-	if (rq->cmd == IDETAPE_WRITE_REQUEST)
-		idetape_copy_buffer_from_stage (stage,tape->data_buffer);
-	
-	rq->buffer=tape->data_buffer;
-	tape->active_data_request=rq;
-	tape->active_stage=stage;
-	tape->next_stage=stage->next;
+	ide_unregister_module(&idetape_module);
 }
+#endif /* MODULE */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov