patch-2.1.20 linux/drivers/char/tpqic02.c

Next file: linux/drivers/char/tty_io.c
Previous file: linux/drivers/char/esp.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.19/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
@@ -1,12 +1,9 @@
-/* $Id: tpqic02.c,v 0.4.1.5 1994/10/29 02:46:13 root Exp root $
+/* $Id: tpqic02.c,v 0.7.1.5 1996/12/14 22:58:52 root Exp root $
  *
- * Driver for tape drive support for Linux-i386 1.1.58
+ * Driver for tape drive support for Linux-i386
  *
- * Copyright (c) 1992, 1993, 1994 by H. H. Bergman. All rights reserved.
- * Current e-mail address: hennus@sky.ow.org [This is a UUCP link.]
- * [If you are unable to reach me directly, try the TAPE mailing list
- * channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as
- * the first line in your message.]
+ * Copyright (c) 1992--1996 by H. H. Bergman. All rights reserved.
+ * Current e-mail address: hennus@cybercomm.nl
  *
  * Distribution of this program in executable form is only allowed if
  * all of the corresponding source files are made available through the same
@@ -33,154 +30,28 @@
  *
  * You are not allowed to change this line nor the text above.
  *
- * $Log: tpqic02.c,v $
- * Revision 0.4.1.5  1994/10/29  02:46:13  root
- * Minor cleanups.
+ * 1996/10/10   Emerald changes
  *
- * Revision 0.4.1.4  1994/07/21  02:15:45  root
- * ifdef'd DDI. Exception masks.
+ * 1996/05/21	Misc changes+merges+cleanups + I/O reservations
  *
- * Revision 0.4.1.3  1994/05/03  01:49:09  root
- * Initial attempt at Mountain support for the Mountain 7150.
- * Based on patches provided by Erik Jacobson.
+ * 1996/05/20	Module support patches submitted by Brian McCauley.
  *
- * Revision 0.4.1.2  1994/03/18  21:16:50  root
- * Many driver messages can now be turned off (runtime selectable).
+ * 1994/05/03	Initial attempt at Mountain support for the Mountain 7150.
+ * Based on patches provided by Erik Jacobson. Still incomplete, I suppose.
  *
- * Revision 0.4.1.1  1994/02/16  19:47:22  root
- * First stab at runtime debug-variable.
+ * 1994/02/07	Archive changes & some cleanups by Eddy Olk.
  *
- * Revision 0.4  1994/02/15  01:53:16  root
- * DYNCONF mark II.
- * Minor cleanups.
+ * 1994/01/19	Speed measuring stuff moved from aperf.h to delay.h.
+ *		BogoMips (tm) introduced by Linus.
  *
- * Revision 0.3  1994/02/07  01:23:16  root
- * More improved DYNCONF.
- * Archive changes & some cleanups by Eddy Olk.
- * Removed status_open, more cleanups, misc other.
- *
- * Revision 0.2.1.25  1994/01/24  02:01:33  root
- * Changed tape_qic02 to QIC02_TAPE.
- * Changes to prepare for DYNCONF.
- *
- * Revision 0.2.1.24  1994/01/23  07:27:18  root
- * Attempt to remove compilation warnings, G++ bug,
- * Linus changed TAPE_QIC02 to QIC02_TAPE.
- *
- * Revision 0.2.1.23  1994/01/20  23:49:28  root
- * Changed some exception decoding stuff.
- * TP_HAVE_SEEK, TP_HAVE_DENS. byte_swap_w() on arg, not global.
- * Attempt to fix cartridge-changed-problem for 2150L.
- * Release irq and dma reservations if initial reset fails.
- *
- * Revision 0.2.1.22  1994/01/19  20:56:55  root
- * Speed measuring stuff moved from aperf.h to delay.h.
- * BogoMips (tm) introduced by Linus.
- *
- * Revision 0.2.1.21  1993/06/18  19:04:33  root
- * minor fixes for 0.99.10.
- *
- * Revision 0.2.1.20  1993/06/11  21:38:51  root
- * Added exception code for status 0x8000 (Cypher weirdness).
- *
- * Revision 0.2.1.19  1993/04/19  23:13:59  root
- * Cleanups. Changed to 0.99.8.
- *
- * Revision 0.2.1.18  1993/03/22  17:39:47  root
- * Moved to 0.99.7. Added Archive MTSEEK and MTTELL support.
- *
- * Revision 0.2.1.17  1993/03/08  18:51:59  root
- * Tried to `fix' write-once bug in previous release.
- *
- * Revision 0.2.1.16  1993/03/01  00:06:16  root
- * Use register_chrdev() for 0.99.6.
- *
- * Revision 0.2.1.15  1993/02/25  00:14:25  root
- * minor cleanups.
- *
- * Revision 0.2.1.14  1993/01/25  00:06:14  root
- * Kernel udelay. Eof fixups.
- * Removed report_ read/write dummies; have strace(1) now.
- *
- * Revision 0.2.1.13  1993/01/10  02:24:43  root
- * Rewrote wait_for_ready() to use newer schedule() features.
- * This improves performance for rewinds etc.
- *
- * Revision 0.2.1.12  1993/01/05  18:44:09  root
- * Changes for 0.99.1. Fixed `restartable reads'.
- *
- * Revision 0.2.1.11  1992/11/28  01:19:10  root
- * Changes to exception handling (significant).
- * Changed returned error codes. Hopefully they're correct now.
- * Changed declarations to please gcc-2.3.1.
- * Patch to deal with bogus interrupts for Archive cards.
- *
- * Revision 0.2.1.10  1992/10/28  00:50:44  root
- * underrun/error counter needed byte swapping.
- *
- * Revision 0.2.1.9  1992/10/15  17:06:01  root
- * Removed online() stuff. Changed EOF handling.
- *
- * Revision 0.2.1.8  1992/10/02  22:25:48  root
- * Removed `no_sleep' parameters (got usleep() now),
- * cleaned up some comments.
- *
- * Revision 0.2.1.7  1992/09/27  01:41:55  root
- * Changed write() to do entire user buffer in one go, rather than just
- * a kernel-buffer sized portion each time.
- *
- * Revision 0.2.1.6  1992/09/21  02:15:30  root
- * Introduced udelay() function for microsecond-delays.
- * Trying to use get_dma_residue rather than TC flags.
- * Patch to fill entire user buffer on reads before
- * returning.
- *
- * Revision 0.2.1.5  1992/09/19  02:31:28  root
- * Some changes based on patches by Eddy Olk to
- * support Archive SC402/SC499R controller cards.
- *
- * Revision 0.2.1.4  1992/09/07  01:37:37  root
- * Minor changes
- *
- * Revision 0.2.1.3  1992/08/13  00:11:02  root
- * Added some support for Archive SC402 and SC499 cards.
- * (Untested.)
- *
- * Revision 0.2.1.2  1992/08/10  02:02:36  root
- * Changed from linux/system.h macros to asm/dma.h inline functions.
- *
- * Revision 0.2.1.1  1992/08/08  01:12:39  root
- * cleaned up a bit. added stuff for selftesting.
- * preparing for asm/dma.h instead of linux/system.h
- *
- * Revision 0.2  1992/08/03  20:11:30  root
- * Changed to use new IRQ allocation. Padding now done at runtime, pads to
- * 512 bytes. Because of this the page regs must be re-programmed every
- * block! Added hooks for selftest commands.
- * Moved to linux-0.97.
- *
- * Revision 0.1.0.5  1992/06/22  22:20:30  root
- * moved to Linux 0.96b
- *
- * Revision 0.1.0.4  1992/06/18  02:00:04  root
- * Use minor bit-7 to enable/disable printing of extra debugging info
- * when do tape access.
- * Added semop stuff for DMA/IRQ allocation checking. Don't think this
- * is the right way to do it though.
- *
- * Revision 0.1.0.3  1992/06/01  01:57:34  root
- * changed DRQ to DMA. added TDEBUG ifdefs to reduce output.
- *
- * Revision 0.1.0.2  1992/05/31  14:02:38  root
- * changed SET_DMA_PAGE handling slightly.
- *
- * Revision 0.1.0.1  1992/05/27  12:12:03  root
- * Can now use multiple files on tape (sort of).
- * First release.
+ * 1993/01/25	Kernel udelay. Eof fixups.
+ * 
+ * 1992/09/19	Some changes based on patches by Eddy Olk to support
+ * 		Archive SC402/SC499R controller cards.
  *
- * Revision 0.1  1992/05/26  01:16:31  root
- * Initial version. Copyright H. H. Bergman 1992
+ * 1992/05/27	First release.
  *
+ * 1992/05/26	Initial version. Copyright H. H. Bergman 1992
  */
 
 /* After the legalese, now the important bits:
@@ -200,14 +71,10 @@
 
 #define REALLY_SLOW_IO		/* it sure is ... */
 
+#include <linux/module.h>
+
 #include <linux/config.h>
 
-#ifdef MODULE
-  #ifdef CONFIG_QIC02_DYNCONF
-    #error dynamic configuration as module not implemented!
-  #endif
-#endif
- 
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -218,6 +85,7 @@
 #include <linux/mtio.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
+#include <linux/ioport.h>
 #include <linux/tpqic02.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
@@ -227,14 +95,9 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-/* We really shouldn't be using this define.. */
-#define IOCCMD_MASK 0x0000ffff
-
 /* check existence of required configuration parameters */
-#if !defined(QIC02_CMD_PORT) || \
-    !defined(QIC02_TAPE_IRQ) || \
-    !defined(QIC02_TAPE_DMA)
-#error qic02_tape configuration error
+#if !defined(QIC02_CMD_PORT) || !defined(QIC02_TAPE_IRQ) || !defined(QIC02_TAPE_DMA)
+# error qic02_tape configuration error
 #endif
 
 
@@ -248,17 +111,19 @@
 /* This holds the dynamic configuration info for the interface
  * card+drive info if runtime configuration has been selected.
  */
-struct mtconfiginfo qic02_tape_dynconf = { 0, };	/* user settable */
-struct qic02_ccb qic02_tape_ccb = { 0, };		/* private stuff */
+
+static struct mtconfiginfo qic02_tape_dynconf = 	/* user settable */
+    { 0, 0, BOGUS_IRQ, 0, 0, TPQD_DEFAULT_FLAGS, };
+static struct qic02_ccb qic02_tape_ccb = { 0, };	/* private stuff */
 
 #else
 
-unsigned long qic02_tape_debug;
+unsigned long qic02_tape_debug = TPQD_DEFAULT_FLAGS;
 
 # if ((QIC02_TAPE_IFC!=WANGTEK) && (QIC02_TAPE_IFC!=ARCHIVE) && (QIC02_TAPE_IFC!=MOUNTAIN))
 #  error No valid interface card specified
 # endif
-#endif
+#endif /* CONFIG_QIC02_DYNCONF */
 
 static volatile int ctlbits = 0;     /* control reg bits for tape interface */
 
@@ -268,8 +133,8 @@
 
 static volatile struct tpstatus tperror;	/* last drive status */
 
-static char rcs_revision[] = "$Revision: 0.4.1.5 $";
-static char rcs_date[] = "$Date: 1994/10/29 02:46:13 $";
+static char rcs_revision[] = "$Revision: 0.7.1.5 $";
+static char rcs_date[] = "$Date: 1996/12/14 22:58:52 $";
 
 /* Flag bits for status and outstanding requests.
  * (Could all be put in one bit-field-struct.)
@@ -330,27 +195,17 @@
  */
 static int  mode_access;	/* access mode: READ or WRITE */
 
+static int qic02_get_resources(void);
+static void qic02_release_resources(void);
 
-/* This is the actual kernel buffer where the interrupt routines read
- * from/write to. It is needed because the DMA channels 1 and 3 cannot
+/* This is a pointer to the actual kernel buffer where the interrupt routines
+ * read from/write to. It is needed because the DMA channels 1 and 3 cannot
  * always access the user buffers. [The kernel buffer must reside in the
- * lower 16MBytes of system memory because of the DMA controller.]
- * The user must ensure that a large enough buffer is passed to the
- * kernel, in order to reduce tape repositioning.
- *
- * The buffer is 512 bytes larger than expected, because I want to align it
- * at 512 bytes, to prevent problems with 64k boundaries.
+ * lower 16MBytes of system memory because of the DMA controller.] The user
+ * must ensure that a large enough buffer is passed to the kernel, in order
+ * to reduce tape repositioning wear and tear.
  */
-
-#ifdef MODULE
-static char *qic02_tape_buf = NULL;
-#else
-static volatile char qic02_tape_buf[TPQBUF_SIZE+TAPE_BLKSIZE];
-/* A really good compiler would be able to align this at 512 bytes... :-( */
-#endif /* MODULE */
-
-static unsigned long buffaddr;	/* aligned physical address of buffer */
-
+static unsigned long buffaddr = 0;	/* physical address of buffer */
 
 /* This translates minor numbers to the corresponding recording format: */
 static const char *format_names[] = {
@@ -436,7 +291,15 @@
 };
 #define NR_OF_EXC	(sizeof(exception_list)/sizeof(struct exception_list_type))
 
-
+/* Compare expected struct size and actual struct size. This
+ * is useful to catch programs compiled with old #includes.
+ */
+#define CHECK_IOC_SIZE(structure) \
+	if (_IOC_SIZE(iocmd) != sizeof(struct structure)) { \
+		tpqputs(TPQD_ALWAYS, "sizeof(struct " #structure \
+			") does not match!"); \
+		return -EFAULT; \
+	} \
 
 static void tpqputs(unsigned long flags, const char *s)
 {
@@ -445,8 +308,6 @@
 } /* tpqputs */
 
 
-
-
 /* Perform byte order swapping for a 16-bit word.
  *
  * [FIXME] This should probably be in include/asm/
@@ -468,27 +329,36 @@
  */
 static void ifc_init(void)
 {
-	if (QIC02_TAPE_IFC == WANGTEK) /* || (QIC02_TAPE_IFC == EVEREX) */ {
-		ctlbits = WT_CTL_ONLINE;	/* online */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-
-	} else if (QIC02_TAPE_IFC == ARCHIVE) {
-		ctlbits = 0;			/* no interrupts yet */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-		outb_p(0, AR_RESET_DMA_PORT);	/* dummy write to reset DMA */
-
-	} else /* MOUNTAIN */ {
-		ctlbits = MTN_CTL_ONLINE;       /* online, and logic enabled */
-		outb_p(ctlbits, QIC02_CTL_PORT);
-	}
+    if (QIC02_TAPE_IFC == WANGTEK) /* || (QIC02_TAPE_IFC == EVEREX) */
+    {
+	ctlbits = WT_CTL_ONLINE;	/* online */
+	outb_p(ctlbits, QIC02_CTL_PORT);
+    }
+    else if (QIC02_TAPE_IFC == ARCHIVE)
+    {
+	ctlbits = 0;			/* no interrupts yet */
+	outb_p(ctlbits, QIC02_CTL_PORT);
+	outb_p(0, AR_RESET_DMA_PORT);	/* dummy write to reset DMA */
+    }
+    else /* MOUNTAIN */
+    {
+	ctlbits = MTN_CTL_ONLINE;       /* online, and logic enabled */
+	outb_p(ctlbits, QIC02_CTL_PORT);
+    }
 } /* ifc_init */
 
 
 static void report_qic_exception(unsigned n)
 {
-	if (n >= NR_OF_EXC) { tpqputs(TPQD_ALWAYS, "Oops -- report_qic_exception"); n = 0; }
-	if (TPQDBG(SENSE_TEXT) || n==0)
-		printk(TPQIC02_NAME ": sense: %s\n", exception_list[n].msg);
+    if (n >= NR_OF_EXC)
+    {
+	tpqputs(TPQD_ALWAYS, "Oops -- report_qic_exception");
+	n = 0;
+    }
+    if (TPQDBG(SENSE_TEXT) || n==0)
+    {
+	printk(TPQIC02_NAME ": sense: %s\n", exception_list[n].msg);
+    }
 } /* report_qic_exception */
 
 
@@ -499,126 +369,63 @@
  */
 static int decode_qic_exception_nr(unsigned s)
 {
-	int i;
+    int i;
 
-	for (i=1; i<NR_OF_EXC; i++) {
-		if ((s & exception_list[i].mask)==exception_list[i].code)
-			return i;
+    for (i=1; i<NR_OF_EXC; i++)
+    {
+	if ((s & exception_list[i].mask)==exception_list[i].code)
+	{
+	    return i;
 	}
-	printk(TPQIC02_NAME ": decode_qic_exception_nr: exception(%x) not recognized\n", s);
-	return 0;
+    }
+    printk(TPQIC02_NAME ": decode_qic_exception_nr: exception(%x) not recognized\n", s);
+    return 0;
 } /* decode_qic_exception_nr */
 
 
-#ifdef OBSOLETE
-/* There are exactly 14 possible exceptions, as defined in QIC-02 rev F.
- * Some are FATAL, some aren't. Currently all exceptions are treated as fatal.
- * Especially 6 and 14 should not abort the transfer. RSN...
- * Should probably let sense() figure out the exception number using the code
- * below, and just report the error based on the number here, returning a code
- * for FATAL/CONTINUABLE.
- */
-static void report_error(int s)
-{
-	short n = -1;
-
-	if (s & TP_ST1) {
-		if (s & TP_ILL)		/* 12: Illegal command. FATAL */
-			n = 12;
-		if (s & TP_POR)		/* 13: Reset occurred. FATAL */
-			n = 13;
-	} 
-	else if (s & TP_ST0) {
-		if (s & TP_EOR) {	/* extra: 15: End of Recorded Media. CONTINUABLE */
-			n = 15;
-			/********** should set flag here **********/
-		}
-		else if (s & TP_EOM)		/* 4: End Of Media. CONTINUABLE */
-			n = 4;
-		else if (s & TP_USL)		/* 2: Drive not online. FATAL */
-			n = 2;
-		else if (s & TP_CNI) {	/* 1: Cartridge not in place. FATAL */
-			n = 1;
-			need_rewind = YES;
-			status_eof_detected = NO;
-			status_eom_detected = NO;
-		}
-		else if (s & TP_UDA) {
-			if (s & TP_BNL) {
-				if (s & TP_NDT) {
-					if (s & TP_BOM)		/* 9: Read error. No data detected & EOM. CONTINUABLE */
-						n = 9;
-					else if (s & TP_EOM)	/* 10: Read error. No data detected & BOM. CONTINUABLE */
-						n = 10;
-					else			/* 8: Read error. No data detected. CONTINUABLE */
-						n = 8;
-				} else { /* 7: Read error. Cannot recover block, filler substituted. CONTINUABLE */
-					tpqputs(TPQD_ALWAYS, "[Bad block -- filler data transferred.]");
-					n = 7;
-				}
-			}
-			else {
-				if (s & TP_EOM)	/* 5: Read or Write error. Rewind tape. FATAL */
-					n = 5;
-				else {		/* 6: Read error. Bad block transferred. CONTINUABLE */
-					/* block is bad, but transfer may continue.
-					 * This is why some people prefer not to
-					 * use compression on backups...
-					 */
-					tpqputs(TPQD_ALWAYS, "[CRC failed!]");
-					n = 6;
-				}
-			}
-		}
-		else if (s & TP_FIL) {
-			if (s & TP_MBD) {	/* 14: Marginal block detected. CONTINUABLE */
-				tpqputs(TPQD_ALWAYS, "[Marginal block]");
-				n = 14;
-			} else			/* 11: File mark detected. CONTINUABLE */
-				n = 11;
-		}
-		else if (s & TP_WRP)		/* 3: Write protected cartridge. FATAL */
-			n = 3;
-	}
-	if (n >= 0)
- 		sensemsg(n);
-} /* report_error */
-#endif
-
 
 /* Perform appropriate action for certain exceptions.
  * should return a value to indicate stop/continue (in case of bad blocks)
  */
 static void handle_qic_exception(int exnr, int exbits)
 {
-	if (exnr==EXC_NCART) {
-		/* Cartridge was changed. Redo sense().
-		 * EXC_NCART should be handled in open().
-		 * It is not permitted to remove the tape while
-		 * the tape driver has open files. 
-		 */
-		need_rewind = YES;
-		status_eof_detected = NO;
-		status_eom_detected = NO;
-	}
-	else if (exnr==EXC_XFILLER)
-		tpqputs(TPQD_ALWAYS, "[Bad block -- filler data transferred.]");
-	else if (exnr==EXC_XBAD)
-		tpqputs(TPQD_ALWAYS, "[CRC failed!]");
-	else if (exnr==EXC_MARGINAL) {
-		/* A marginal block behaves much like a FM.
-		 * User may continue reading, if desired.
-		 */
-		tpqputs(TPQD_ALWAYS, "[Marginal block]");
-		doing_read = NO;
-	} else if (exnr==EXC_FM)
-		doing_read = NO;
+    if (exnr==EXC_NCART)
+    {
+	/* Cartridge was changed. Redo sense().
+	 * EXC_NCART should be handled in open().
+	 * It is not permitted to remove the tape while
+	 * the tape driver has open files. 
+	 */
+	need_rewind = YES;
+	status_eof_detected = NO;
+	status_eom_detected = NO;
+    }
+    else if (exnr==EXC_XFILLER)
+    {
+	tpqputs(TPQD_ALWAYS, "[Bad block -- filler data transferred.]");
+    }
+    else if (exnr==EXC_XBAD)
+    {
+	tpqputs(TPQD_ALWAYS, "[CRC failed!]");
+    }
+    else if (exnr==EXC_MARGINAL)
+    {
+	/* A marginal block behaves much like a FM.
+	 * User may continue reading, if desired.
+	 */
+	tpqputs(TPQD_ALWAYS, "[Marginal block]");
+	doing_read = NO;
+    }
+    else if (exnr==EXC_FM)
+    {
+	doing_read = NO;
+    }
 } /* handle_qic_exception */
 
 
 static inline int is_exception(void)
 {
-	return (inb(QIC02_STAT_PORT) & QIC02_STAT_EXCEPTION) == 0;
+    return (inb(QIC02_STAT_PORT) & QIC02_STAT_EXCEPTION) == 0;
 } /* is_exception */
 
 
@@ -628,41 +435,53 @@
  */
 static int tape_reset(int verbose)
 {
-	ifc_init();				/* reset interface card */
-
-	/* assert reset */
-	if (QIC02_TAPE_IFC == MOUNTAIN)
-		outb_p(ctlbits & ~MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
-	else /* WANGTEK, ARCHIVE */
- 		outb_p(ctlbits | QIC02_CTL_RESET, QIC02_CTL_PORT);
-
-	/* Next, we need to wait >=25 usec. */
-	udelay(30);
+    ifc_init();				/* reset interface card */
 
-	/* after reset, we will be at BOT (modulo an automatic rewind) */
-	status_eof_detected = NO;
-	status_eom_detected = NO;
-	status_cmd_pending = 0;
-	need_rewind = YES;
-	doing_read = doing_write = NO;
-	ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
-
-	/* de-assert reset */
-	if (QIC02_TAPE_IFC == MOUNTAIN)
-		outb_p(ctlbits | MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
-	else
-		outb_p(ctlbits & ~QIC02_CTL_RESET, QIC02_CTL_PORT);
-
-	/* KLUDGE FOR G++ BUG */
-	{ int stat = inb_p(QIC02_STAT_PORT);
-	  status_dead = ((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL); }
-	/* if successful, inb(STAT) returned RESETVAL */
-	if (status_dead == YES)
-		printk(TPQIC02_NAME ": reset failed!\n");
-	else if (verbose)
-		printk(TPQIC02_NAME ": reset successful\n");
-
-	return (status_dead == YES)? TE_DEAD : TE_OK;
+    /* assert reset */
+    if (QIC02_TAPE_IFC == MOUNTAIN)
+    {
+	outb_p(ctlbits & ~MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
+    }
+    else /* WANGTEK, ARCHIVE */
+    {
+	outb_p(ctlbits | QIC02_CTL_RESET, QIC02_CTL_PORT);
+    }
+    
+    /* Next, we need to wait >=25 usec. */
+    udelay(30);
+
+    /* after reset, we will be at BOT (modulo an automatic rewind) */
+    status_eof_detected = NO;
+    status_eom_detected = NO;
+    status_cmd_pending = 0;
+    need_rewind = YES;
+    doing_read = doing_write = NO;
+    ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
+    
+    /* de-assert reset */
+    if (QIC02_TAPE_IFC == MOUNTAIN)
+    {
+	outb_p(ctlbits | MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
+    }
+    else
+    {
+	outb_p(ctlbits & ~QIC02_CTL_RESET, QIC02_CTL_PORT);
+    }
+    
+    /* KLUDGE FOR G++ BUG */
+    { int stat = inb_p(QIC02_STAT_PORT);
+	status_dead = ((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL); }
+    /* if successful, inb(STAT) returned RESETVAL */
+    if (status_dead == YES)
+    {
+	printk(TPQIC02_NAME ": reset failed!\n");
+    }
+    else if (verbose)
+    {
+	printk(TPQIC02_NAME ": reset successful\n");
+    }
+    
+    return (status_dead == YES)? TE_DEAD : TE_OK;
 } /* tape_reset */
 
 
@@ -1852,9 +1671,10 @@
 		 * if dma channel hasn't finished last byte yet.
 		 */
 		r = 0;
-/* Skip next ready check for Archive controller because
- * it may be busy reading ahead. Weird. --hhb
- */
+
+	    /* Skip next ready check for Archive controller because
+	     * it may be busy reading ahead. Weird. --hhb
+	     */
 		if (QIC02_TAPE_IFC == WANGTEK)	/* I think this is a drive-dependency, not IFC -- hhb */
 			if (stat & QIC02_STAT_READY) {		/* not ready */
 				tpqputs(TPQD_ALWAYS, "isr: ? Tape controller not ready");
@@ -1892,7 +1712,7 @@
 
 
 static long long qic02_tape_lseek(struct inode * inode, struct file * file,
-	long long offset, int origin)
+				  long long offset, int origin)
 {
 	return -EINVAL;	/* not supported */
 } /* qic02_tape_lseek */
@@ -1931,145 +1751,187 @@
  */
 
 static long qic02_tape_read(struct inode * inode, struct file * filp,
-	char * buf, unsigned long count)
+			    char * buf, unsigned long count)
 {
-	kdev_t dev = inode->i_rdev;
-	unsigned short flags = filp->f_flags;
-	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
-	int stat;
-
-	if (status_zombie==YES) {
-		tpqputs(TPQD_ALWAYS, "configs not set");		
-		return -ENXIO;
-	}
+    int err;
+    kdev_t dev = inode->i_rdev;
+    unsigned short flags = filp->f_flags;
+    unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
+    int stat;
+
+    if (status_zombie==YES)
+    {
+	tpqputs(TPQD_ALWAYS, "configs not set");		
+	return -ENXIO;
+    }
+
+    if (TP_DIAGS(current_tape_dev))
+      /* can't print a ``long long'' (for filp->f_pos), so chop it */
+      printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n",
+	     MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
+    
+    if (count % TAPE_BLKSIZE)	/* Only allow mod 512 bytes at a time. */
+    {
+	tpqputs(TPQD_BLKSZ, "Wrong block size");
+	return -EINVAL;
+    }
 
-	if (TP_DIAGS(current_tape_dev))
-		/* can't print a ``long long'' (for filp->f_pos), so chop it */
-		printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n",
-			MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
+    /* Just assume everything is ok. Controller will scream if not. */
 
-	if (count % TAPE_BLKSIZE) {	/* Only allow mod 512 bytes at a time. */
-		tpqputs(TPQD_BLKSZ, "Wrong block size");
-		return -EINVAL;
+    if (status_bytes_wr)	/* Once written, no more reads, 'till after WFM. */
+    {
+	return -EACCES;
+    }
+    
+    /* This is rather ugly because it has to implement a finite state
+     * machine in order to handle the EOF situations properly.
+     */
+    while ((signed)count>=0)
+    {
+	bytes_done = 0;
+	/* see how much fits in the kernel buffer */
+	bytes_todo = TPQBUF_SIZE;
+	if (bytes_todo>count)
+	{
+	    bytes_todo = count;
 	}
-
-	/* Just assume everything is ok. Controller will scream if not. */
-
-	if (status_bytes_wr)	/* Once written, no more reads, 'till after WFM. */
-		return -EACCES;
-
-	/* This is rather ugly because it has to implement a finite state
-	 * machine in order to handle the EOF situations properly.
-	 */
-	while ((signed)count>=0) {
-		bytes_done = 0;
-		/* see how much fits in the kernel buffer */
-		bytes_todo = TPQBUF_SIZE;
-		if (bytes_todo>count)
-			bytes_todo = count;
-
-		/* Must ensure that user program sees exactly one EOF token (==0) */
-		if (return_read_eof==YES) {
-			if (TPQDBG(DEBUG))
-				printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n", return_read_eof, reported_read_eof, total_bytes_done);
-
-			if (reported_read_eof==NO) {
-				/* have not yet returned EOF to user program */
-				if (total_bytes_done>0) {
-					return total_bytes_done; /* next time return EOF */
-				} else {
-					reported_read_eof = YES; /* move on next time */
-					return 0;		 /* return EOF */
-				}				
-			} else {
-				/* Application program has already received EOF
-				 * (above), now continue with next file on tape,
-				 * if possible.
-				 * When the FM is reached, EXCEPTION is set,
-				 * causing a sense(). Subsequent read/writes will
-				 * continue after the FM.
-				 */
-/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/
-				if (status_eom_detected)
-					/* If EOM, nothing left to read, so keep returning EOFs.
-					 *** should probably set some flag to avoid clearing
-					 *** status_eom_detected through ioctls or something
-					 */
-					return 0;
-				else {
-					/* just eof, there may be more files ahead... */
-					return_read_eof = NO;
-					reported_read_eof = NO;
-					status_eof_detected = NO; /* reset this too */
-					/*fall through*/
-				}
-			}
+	
+	/* Must ensure that user program sees exactly one EOF token (==0) */
+	if (return_read_eof==YES)
+	{
+	    if (TPQDBG(DEBUG))
+	    {
+		printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n", return_read_eof, reported_read_eof, total_bytes_done);
+	    }
+	    
+	    if (reported_read_eof==NO)
+	    {
+		/* have not yet returned EOF to user program */
+		if (total_bytes_done>0)
+		{
+		    return total_bytes_done; /* next time return EOF */
 		}
-
-/*****************************/
-		if (bytes_todo==0)
-			return total_bytes_done;
-
-		if (bytes_todo>0) {
-			/* start reading data */
-			if (is_exception())	/****************************************/
-				tpqputs(TPQD_DMAX, "is_exception() before start_dma()!");
+		else
+		{
+		    reported_read_eof = YES; /* move on next time */
+		    return 0;		 /* return EOF */
+		}				
+	    }
+	    else
+	    {
+		/* Application program has already received EOF
+		 * (above), now continue with next file on tape,
+		 * if possible.
+		 * When the FM is reached, EXCEPTION is set,
+		 * causing a sense(). Subsequent read/writes will
+		 * continue after the FM.
+		 */
+		/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/
+		if (status_eom_detected)
+		{
+		    /* If EOM, nothing left to read, so keep returning EOFs.
+		     *** should probably set some flag to avoid clearing
+		     *** status_eom_detected through ioctls or something
+		     */
+		    return 0;
+		}
+		else
+		{
+		    /* just eof, there may be more files ahead... */
+		    return_read_eof = NO;
+		    reported_read_eof = NO;
+		    status_eof_detected = NO; /* reset this too */
+		    /*fall through*/
+		}
+	    }
+	}
+	
+	/*****************************/
+	if (bytes_todo==0)
+	{
+	    return total_bytes_done;
+	}
+	
+	if (bytes_todo>0)
+	{
+	    /* start reading data */
+	    if (is_exception())	/****************************************/
+	    {
+		tpqputs(TPQD_DMAX, "is_exception() before start_dma()!");
+	    }
+	    
 /******************************************************************
  ***** if start_dma() fails because the head is positioned 0 bytes
  ***** before the FM, (causing EXCEPTION to be set) return_read_eof should
  ***** be set to YES, and we should return total_bytes_done, rather than -ENXIO.
  ***** The app should recognize this as an EOF condition.
  ***************************************************************************/
-			stat = start_dma(READ, bytes_todo);
-			if (stat == TE_OK) {
-				/* Wait for transfer to complete, interrupt should wake us */
-				while (dma_mode != 0) {
-					sleep_on(&qic02_tape_transfer);
-				}
-				if (status_error)
-					return_read_eof = YES;
-			} else if (stat != TE_END) {
-				/* should do sense() on error here */
+	    stat = start_dma(READ, bytes_todo);
+	    if (stat == TE_OK)
+	    {
+		/* Wait for transfer to complete, interrupt should wake us */
+		while (dma_mode != 0)
+		{
+		    sleep_on(&qic02_tape_transfer);
+		}
+		if (status_error)
+		{
+		    return_read_eof = YES;
+		}
+		
+	    }
+	    else if (stat != TE_END)
+	    {
+		/* should do sense() on error here */
 #if 0
-				return -ENXIO;
+		return -ENXIO;
 #else
-				printk("Trouble: stat==%02x\n", stat);
-				return_read_eof = YES;
-				/*************** check EOF/EOT handling!!!!!! **/
-#endif
-			}
-			end_dma(&bytes_done);
-			if (bytes_done>bytes_todo) {
-				tpqputs(TPQD_ALWAYS, "read: Oops, read more bytes than requested");
-				return -EIO;
-			}
-			/* copy buffer to user-space in one go */
-			if (bytes_done>0)
-				if (copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), 
-						bytes_done))
-					return -EFAULT;
-
-#if 1
-			/* Checks Ton's patch below */
-			if ((return_read_eof == NO) && (status_eof_detected == YES)) {
-				printk(TPQIC02_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof);
-			}
-#endif
-			if ((bytes_todo != bytes_done) || (status_eof_detected == YES))
-				/* EOF or EOM detected. return EOF next time. */
-				return_read_eof = YES;
-		} /* else: ignore read request for 0 bytes */
-
-		if (bytes_done>0) {
-			status_bytes_rd = YES;
-			buf += bytes_done;
-			filp->f_pos += bytes_done;
-			total_bytes_done += bytes_done;
-			count -= bytes_done;
+		printk("Trouble: stat==%02x\n", stat);
+		return_read_eof = YES;
+		/*************** check EOF/EOT handling!!!!!! **/
+#endif
+	    }
+	    end_dma(&bytes_done);
+	    if (bytes_done>bytes_todo)
+	    {
+		tpqputs(TPQD_ALWAYS, "read: Oops, read more bytes than requested");
+		return -EIO;
+	    }
+	    /* copy buffer to user-space in one go */
+	    if (bytes_done>0)
+	    {
+		err = copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), bytes_done);
+		if (err)
+		{
+		    return -EFAULT;
 		}
-	}
-	tpqputs(TPQD_ALWAYS, "read request for <0 bytes");
-	return -EINVAL;
+	    }
+#if 1
+	    /* Checks Ton's patch below */
+	    if ((return_read_eof == NO) && (status_eof_detected == YES))
+	    {
+		printk(TPQIC02_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof);
+	    }
+#endif
+	    if ((bytes_todo != bytes_done) || (status_eof_detected == YES))
+	    {
+		/* EOF or EOM detected. return EOF next time. */
+		return_read_eof = YES;
+	    }
+	    
+	} /* else: ignore read request for 0 bytes */
+
+	if (bytes_done>0)
+	{
+	    status_bytes_rd = YES;
+	    buf += bytes_done;
+	    filp->f_pos += bytes_done;
+	    total_bytes_done += bytes_done;
+	    count -= bytes_done;
+	}
+    }
+    tpqputs(TPQD_ALWAYS, "read request for <0 bytes");
+    return -EINVAL;
 } /* qic02_tape_read */
 
 
@@ -2102,77 +1964,98 @@
  * tape device again. The driver will detect an exception status in (No Cartridge)
  * and force a rewind. After that tar may continue writing.
  */
-static long qic02_tape_write(struct inode * inode, struct file * filp,
-	const char * buf, unsigned long count)
+static long qic02_tape_write(struct inode * inode, struct file * filp, 
+			     const char * buf, unsigned long count)
 {
-	kdev_t dev = inode->i_rdev;
-	unsigned short flags = filp->f_flags;
-	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
-
-	if (status_zombie==YES) {
-		tpqputs(TPQD_ALWAYS, "configs not set");		
-		return -ENXIO;
-	}
-
-	if (TP_DIAGS(current_tape_dev))
-		/* can't print a ``long long'' (for filp->f_pos), so chop it */
-		printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n",
-			MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
+    int err;
+    kdev_t dev = inode->i_rdev;
+    unsigned short flags = filp->f_flags;
+    unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
+    
+    if (status_zombie==YES)
+    {
+	tpqputs(TPQD_ALWAYS, "configs not set");		
+	return -ENXIO;
+    }
+
+    if (TP_DIAGS(current_tape_dev))
+    {
+	/* can't print a ``long long'' (for filp->f_pos), so chop it */
+	printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n",
+	       MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
+    }
+    
+    if (count % TAPE_BLKSIZE) 	/* only allow mod 512 bytes at a time */
+    {
+	tpqputs(TPQD_BLKSZ, "Wrong block size");
+	return -EINVAL;
+    }
 
-	if (count % TAPE_BLKSIZE) {	/* only allow mod 512 bytes at a time */
-		tpqputs(TPQD_BLKSZ, "Wrong block size");
-		return -EINVAL;
+    if (mode_access==READ)
+    {
+	tpqputs(TPQD_ALWAYS, "Not in write mode");
+	return -EACCES;
+    }
+
+    /* open() does a sense() and we can assume the tape isn't changed
+     * between open() and release(), so the tperror.exs bits will still
+     * be valid.
+     */
+    if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP))
+    {
+	tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");
+	return -EACCES;	/* don't even try when write protected */
+    }
+      
+    if (doing_read == YES)
+    {
+	terminate_read(0);
+    }
+    
+    while ((signed)count>=0)
+    {
+	/* see how much fits in the kernel buffer */
+	bytes_done = 0;
+	bytes_todo = TPQBUF_SIZE;
+	if (bytes_todo>count)
+	{
+	    bytes_todo = count;
 	}
-
-	if (mode_access==READ) {
-		tpqputs(TPQD_ALWAYS, "Not in write mode");
-		return -EACCES;
+	
+	if (return_write_eof == YES)
+	{
+	    /* return_write_eof should be reset on reverse tape movements. */
+	    
+	    if (reported_write_eof==NO)
+	    {
+		if (bytes_todo>0)
+		{
+		    tpqputs(TPQD_ALWAYS, "partial write");
+		    /* partial write signals EOF to user program */
+		}
+		reported_write_eof = YES;
+		return total_bytes_done;
+	    }
+	    else
+	    {
+		return -ENOSPC;		 /* return error */
+	    }	
 	}
-
-	/* open() does a sense() and we can assume the tape isn't changed
-	 * between open() and release(), so the tperror.exs bits will still
-	 * be valid.
-	 */
-	if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
-		tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");
-		return -EACCES;	/* don't even try when write protected */
+	
+	/* Quit when done. */
+	if (bytes_todo==0)
+	{
+	    return total_bytes_done;
 	}
-
-	if (doing_read == YES)
-		terminate_read(0);
-
-	while ((signed)count>=0) {
-		/* see how much fits in the kernel buffer */
-		bytes_done = 0;
-		bytes_todo = TPQBUF_SIZE;
-		if (bytes_todo>count)
-			bytes_todo = count;
 	
-		if (return_write_eof == YES) {
-			/* return_write_eof should be reset on reverse tape movements. */
-
-			if (reported_write_eof==NO) {
-				if (bytes_todo>0) {
-					tpqputs(TPQD_ALWAYS, "partial write");
-					/* partial write signals EOF to user program */
-				}
-				reported_write_eof = YES;
-				return total_bytes_done;
-			} else {
-				return -ENOSPC;		 /* return error */
-			}	
-		}
-
-		/* Quit when done. */
-		if (bytes_todo==0)
-			return total_bytes_done;
-
-
-		/* copy from user to DMA buffer and initiate transfer. */
-		if (bytes_todo>0) {
-			if (copy_from_user( (void *) bus_to_virt(buffaddr), 
-					(const void *) buf, bytes_todo))
-				return -EFAULT;
+	/* copy from user to DMA buffer and initiate transfer. */
+	if (bytes_todo>0)
+	{
+	    err = copy_from_user( (void *) bus_to_virt(buffaddr), (const void *) buf, bytes_todo);
+	    if (err)
+	    {
+		return -EFAULT;
+	    }
 
 /****************** similar problem with read() at FM could happen here at EOT.
  ******************/
@@ -2180,62 +2063,75 @@
 /***** if at EOT, 0 bytes can be written. start_dma() will
  ***** fail and write() will return ENXIO error
  *****/
-			if (start_dma(WRITE, bytes_todo) != TE_OK) {
-				tpqputs(TPQD_ALWAYS, "write: start_dma() failed");
-				/* should do sense() on error here */
-				return -ENXIO;	/*********** FIXTHIS **************/
-			}
-
-			/* Wait for write to complete, interrupt should wake us. */
-			while ((status_error == 0) && (dma_mode != 0)) {
-				sleep_on(&qic02_tape_transfer);
-			}
-
-			end_dma(&bytes_done);
-			if (bytes_done>bytes_todo) {
-				tpqputs(TPQD_ALWAYS, "write: Oops, wrote more bytes than requested");
-				return -EIO;
-			}
-			/* If the dma-transfer was aborted because of an exception,
-			 * status_error will have been set in the interrupt handler.
-			 * Then end_dma() will do a sense().
-			 * If the exception was EXC_EOM, the EW-hole was encountered
-			 * and two more blocks could be written. For the time being we'll
-			 * just consider this to be the EOT.
-			 * Otherwise, something Bad happened, such as the maximum number
-			 * of block-rewrites was exceeded. [e.g. A very bad spot on tape was
-			 * encountered. Normally short dropouts are compensated for by
-			 * rewriting the block in error, up to 16 times. I'm not sure
-			 * QIC-24 drives can do this.]
-			 */
-			if (status_error) {
-				if (status_eom_detected == YES)	{
-					tpqputs(TPQD_ALWAYS, "write: EW detected");
-					return_write_eof = YES;
-				} else {
-					/* probably EXC_RWA */
-					tpqputs(TPQD_ALWAYS, "write: dma: error in writing");
-					return -EIO;
-				}
-			}
-			if (bytes_todo != bytes_done)
-				/* EOF or EOM detected. return EOT next time. */
-				return_write_eof = YES;
-		}
-		/* else: ignore write request for 0 bytes. */
-
-		if (bytes_done>0) {
-			status_bytes_wr = YES;
-			buf += bytes_done;
-			filp->f_pos += bytes_done;
-			total_bytes_done += bytes_done;
-			count -= bytes_done;
-		}
-	}
-	tpqputs(TPQD_ALWAYS, "write request for <0 bytes");
-	if (TPQDBG(DEBUG))
-		printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %lx\n", status_bytes_wr, buf, total_bytes_done, count);
-	return -EINVAL;
+	    if (start_dma(WRITE, bytes_todo) != TE_OK)
+	    {
+		tpqputs(TPQD_ALWAYS, "write: start_dma() failed");
+		/* should do sense() on error here */
+		return -ENXIO;	/*********** FIXTHIS **************/
+	    }
+
+	    /* Wait for write to complete, interrupt should wake us. */
+	    while ((status_error == 0) && (dma_mode != 0))
+	    {
+		sleep_on(&qic02_tape_transfer);
+	    }
+
+	    end_dma(&bytes_done);
+	    if (bytes_done>bytes_todo)
+	    {
+		tpqputs(TPQD_ALWAYS, "write: Oops, wrote more bytes than requested");
+		return -EIO;
+	    }
+	    /* If the dma-transfer was aborted because of an exception,
+	     * status_error will have been set in the interrupt handler.
+	     * Then end_dma() will do a sense().
+	     * If the exception was EXC_EOM, the EW-hole was encountered
+	     * and two more blocks could be written. For the time being we'll
+	     * just consider this to be the EOT.
+	     * Otherwise, something Bad happened, such as the maximum number
+	     * of block-rewrites was exceeded. [e.g. A very bad spot on tape was
+	     * encountered. Normally short dropouts are compensated for by
+	     * rewriting the block in error, up to 16 times. I'm not sure
+	     * QIC-24 drives can do this.]
+	     */
+	    if (status_error)
+	    {
+		if (status_eom_detected == YES)
+		{
+		    tpqputs(TPQD_ALWAYS, "write: EW detected");
+		    return_write_eof = YES;
+		}
+		else
+		{
+		    /* probably EXC_RWA */
+		    tpqputs(TPQD_ALWAYS, "write: dma: error in writing");
+		    return -EIO;
+		}
+	    }
+	    if (bytes_todo != bytes_done)
+	    {
+		/* EOF or EOM detected. return EOT next time. */
+		return_write_eof = YES;
+	    }
+	}
+	/* else: ignore write request for 0 bytes. */
+	
+	if (bytes_done>0)
+	{
+	    status_bytes_wr = YES;
+	    buf += bytes_done;
+	    filp->f_pos += bytes_done;
+	    total_bytes_done += bytes_done;
+	    count -= bytes_done;
+	}
+    }
+    
+    tpqputs(TPQD_ALWAYS, "write request for <0 bytes");
+    if (TPQDBG(DEBUG))
+    {
+	printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %lx\n", status_bytes_wr, buf, total_bytes_done, count);
+    }
+    return -EINVAL;
 } /* qic02_tape_write */
 
 
@@ -2251,344 +2147,388 @@
  * remembered values, rewind the tape and set the required density.
  * Don't rewind if the minor bits specify density 0.
  */
+
 static int qic02_tape_open(struct inode * inode, struct file * filp)
 {
-	kdev_t dev = inode->i_rdev;
-	unsigned short flags = filp->f_flags;
-	unsigned short dens = 0;
-	int s;
+    static int qic02_tape_open_no_use_count(struct inode *, struct file *);
+    int open_error;
 
+    open_error = qic02_tape_open_no_use_count(inode, filp);
+    if (!open_error)
+    {
+	MOD_INC_USE_COUNT;
+    }
+    return open_error;
+}
 
-	if (TP_DIAGS(dev)) {
-		printk("qic02_tape_open: dev=%s, flags=%x     ",
-		       kdevname(dev), flags);
+static int qic02_tape_open_no_use_count(struct inode * inode, struct file * filp)
+{
+    kdev_t dev = inode->i_rdev;
+    unsigned short flags = filp->f_flags;
+    unsigned short dens = 0;
+    int s;
+
+
+    if (TP_DIAGS(dev))
+    {
+	printk("qic02_tape_open: dev=%s, flags=%x     ",
+	       kdevname(dev), flags);
+    }
+
+    if (MINOR(dev)==255)	/* special case for resetting */
+    {
+	if (suser())
+	{
+	    return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
 	}
-
-#ifdef MODULE
-       MOD_INC_USE_COUNT;
-#endif
-
-	if (MINOR(dev)==255) {	/* special case for resetting */
-#ifdef MODULE
-                MOD_DEC_USE_COUNT;
-#endif
-		if (suser())
-			return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
-		else
-			return -EPERM;
+	else
+	{
+	    return -EPERM;
 	}
-
-	if (status_dead==YES)
-		/* Allow `mt reset' ioctl() even when already open()ed. */
-		return 0;
-
+    }
+    
+    if (status_dead==YES)
+    {
+	/* Allow `mt reset' ioctl() even when already open()ed. */
+	return 0;
+    }
+    
 	/* Only one at a time from here on... */
-	if (filp->f_count>1) {	/* filp->f_count==1 for the first open() */
-#ifdef MODULE
-                MOD_DEC_USE_COUNT;
-#endif
-		return -EBUSY;
-	}
-
-	if (status_zombie==YES)
-		/* no irq/dma/port stuff allocated yet, no reset done
-		 * yet, so return until MTSETCONFIG has been done.
-		 */
-		return 0;
-
-	status_bytes_rd = NO;
-	status_bytes_wr = NO;
-
-	return_read_eof = NO;	/********????????????????*****/
-	return_write_eof = (status_eot_detected)? YES : NO;
-
-	/* Clear this in case user app close()d before reading EOF token */
-	status_eof_detected = NO;
-
-	reported_read_eof = NO;
-	reported_write_eof = NO;
-
-
-	switch (flags & O_ACCMODE) {
-		case O_RDONLY:
-			mode_access = READ;
-			break;
-		case O_WRONLY:	/* Fallthru... Strictly speaking this is not correct... */
-		case O_RDWR:	/* Reads are allowed as long as nothing is written */
-			mode_access = WRITE;
-			break;
-	}
-
-	/* This is to avoid tape-changed problems (TP_CNI exception).
-	 *
-	 * Since removing the cartridge will not raise an exception,
-	 * we always do a tp_sense() to make sure we have the proper
-	 * CNI status, the 2150L may need an additional sense.... - Eddy
-	 */
-	s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
-
-	if (s == TE_OK)
-		/* Try to clear cartridge-changed status for Archive-2150L */
-		if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI))
-			s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
-
-	if (s != TE_OK) {
-		tpqputs(TPQD_ALWAYS, "open: sense() failed");
-#ifdef MODULE
-                MOD_DEC_USE_COUNT;
-#endif
-		return -EIO;
-	}
-
-	/* exception bits should be up-to-date now, so check for
-	 * tape presence and exit if absent.
-	 * Even `mt stat' will fail without a tape.
+    if (filp->f_count>1) 	/* filp->f_count==1 for the first open() */
+    {
+	return -EBUSY;
+    }
+
+    if (status_zombie==YES)
+    {
+	/* no irq/dma/port stuff allocated yet, no reset done
+	 * yet, so return until MTSETCONFIG has been done.
 	 */
-	if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
-		tpqputs(TPQD_ALWAYS, "No tape present.");
-#ifdef MODULE
-                MOD_DEC_USE_COUNT;
-#endif
-		return -EIO;
+	return 0;
+    }
+    
+    status_bytes_rd = NO;
+    status_bytes_wr = NO;
+    
+    return_read_eof = NO;	/********????????????????*****/
+    return_write_eof = (status_eot_detected)? YES : NO;
+
+    /* Clear this in case user app close()d before reading EOF token */
+    status_eof_detected = NO;
+
+    reported_read_eof = NO;
+    reported_write_eof = NO;
+
+
+    switch (flags & O_ACCMODE)
+    {
+     case O_RDONLY:
+	mode_access = READ;
+	break;
+     case O_WRONLY:	/* Fallthru... Strictly speaking this is not correct... */
+     case O_RDWR:	/* Reads are allowed as long as nothing is written */
+	mode_access = WRITE;
+	break;
+    }
+    
+    /* This is to avoid tape-changed problems (TP_CNI exception).
+     *
+     * Since removing the cartridge will not raise an exception,
+     * we always do a tp_sense() to make sure we have the proper
+     * CNI status, the 2150L may need an additional sense.... - Eddy
+     */
+    s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
+    
+    if (s == TE_OK)
+    {
+	/* Try to clear cartridge-changed status for Archive-2150L */
+	if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI))
+	{
+	    s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
 	}
-
-	/* At this point we can assume that a tape is present and
-	 * that it will remain present until release() is called.
+    }
+    
+    if (s != TE_OK)
+    {
+	tpqputs(TPQD_ALWAYS, "open: sense() failed");
+	return -EIO;
+    }
+
+    /* exception bits should be up-to-date now, so check for
+     * tape presence and exit if absent.
+     * Even `mt stat' will fail without a tape.
+     */
+    if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI))
+    {
+	tpqputs(TPQD_ALWAYS, "No tape present.");
+	return -EIO;
+    }
+
+    /* At this point we can assume that a tape is present and
+     * that it will remain present until release() is called.
+     */
+
+    /* not allowed to do QCMD_DENS_* unless tape is rewound */
+    if ((TP_DENS(dev)!=0) && (TP_DENS(current_tape_dev) != TP_DENS(dev)))
+    {
+	/* force rewind if minor bits have changed,
+	 * i.e. user wants to use tape in different format.
+	 * [assuming single drive operation]
 	 */
-
-	/* not allowed to do QCMD_DENS_* unless tape is rewound */
-	if ((TP_DENS(dev)!=0) && (TP_DENS(current_tape_dev) != TP_DENS(dev))) {
-		/* force rewind if minor bits have changed,
-		 * i.e. user wants to use tape in different format.
-		 * [assuming single drive operation]
-		 */
-		if (TP_HAVE_DENS) {
-			tpqputs(TPQD_REWIND, "Density minor bits have changed. Forcing rewind.");
-			need_rewind = YES;
-		}
-	} else {
-		/* density bits still the same, but TP_DIAGS bit 
-		 * may have changed.
-		 */
-		current_tape_dev = dev;
+	if (TP_HAVE_DENS)
+	{
+	    tpqputs(TPQD_REWIND, "Density minor bits have changed. Forcing rewind.");
+	    need_rewind = YES;
 	}
-
-	if (need_rewind == YES) { /***************** CHECK THIS!!!!!!!! **********/
-		s = do_qic_cmd(QCMD_REWIND, TIM_R);
-		if (s != 0) {
-			tpqputs(TPQD_ALWAYS, "open: rewind failed");
-#ifdef MODULE
-			MOD_DEC_USE_COUNT;
-#endif
-			return -EIO;
-		}
+    }
+    else
+    {
+	/* density bits still the same, but TP_DIAGS bit 
+	 * may have changed.
+	 */
+	current_tape_dev = dev;
+    }
+    
+    if (need_rewind == YES)  /***************** CHECK THIS!!!!!!!! **********/
+    {
+	s = do_qic_cmd(QCMD_REWIND, TIM_R);
+	if (s != 0)
+	{
+	    tpqputs(TPQD_ALWAYS, "open: rewind failed");
+	    return -EIO;
 	}
+    }
 
 
 /* Note: After a reset command, the controller will rewind the tape
  *	 just before performing any tape movement operation! ************ SO SET need_rewind flag!!!!!
  */ 
-	if (status_dead==YES) {
-		tpqputs(TPQD_ALWAYS, "open: tape dead, attempting reset");
-		if (tape_reset(1)!=TE_OK) {
-#ifdef MODULE
-			MOD_DEC_USE_COUNT;
-#endif
-			return -ENXIO;
-		} else {
-			status_dead = NO;
-			if (tp_sense(~(TP_ST1|TP_ILL)) != TE_OK) {
-				tpqputs(TPQD_ALWAYS, "open: tp_sense() failed\n");
-				status_dead = YES;	/* try reset next time */
-#ifdef MODULE
-				MOD_DEC_USE_COUNT;
-#endif
-				return -EIO;
-			}
-		}
+    if (status_dead==YES)
+    {
+	tpqputs(TPQD_ALWAYS, "open: tape dead, attempting reset");
+	if (tape_reset(1)!=TE_OK)
+	{
+	    return -ENXIO;
 	}
-
-	/* things should be ok, once we get here */
-
-
-	/* set density: only allowed when TP_BOM status bit is set,
-	 * so we must have done a rewind by now. If not, just skip over.
-	 * Only give set density command when minor bits have changed.
-	 */
-	if (TP_DENS(current_tape_dev) == TP_DENS(dev) )
-		return 0;
-
-	current_tape_dev = dev;
-	need_rewind = NO;
-	if (TP_HAVE_DENS)
-		dens = TP_DENS(dev);
-
-	if (dens < sizeof(format_names)/sizeof(char *))
-		printk(TPQIC02_NAME ": format: %s%s\n", (dens!=0)? "QIC-" : "", format_names[dens]);
 	else
-		tpqputs(TPQD_REWIND, "Wait for retensioning...");
-
-	switch (TP_DENS(dev)) {
-		case 0: /* Minor 0 is for drives without set-density support */
-			s = 0;
-			break;
-		case 1:
-			s = do_qic_cmd(QCMD_DENS_11, TIM_S);
-			break;
-		case 2:
-			s = do_qic_cmd(QCMD_DENS_24, TIM_S);
-			break;
-		case 3:
-			s = do_qic_cmd(QCMD_DENS_120, TIM_S);
-			break;
-		case 4:
-			s = do_qic_cmd(QCMD_DENS_150, TIM_S);
-			break;
-		case 5:
-			s = do_qic_cmd(QCMD_DENS_300, TIM_S);
-			break;
-		case 6:
-			s = do_qic_cmd(QCMD_DENS_600, TIM_S);
-			break;
-		default:  /* otherwise do a retension before anything else */
-			s = do_qic_cmd(QCMD_RETEN, TIM_R);
-	}
-	if (s != 0) {
-		status_dead = YES;	/* force reset */
-		current_tape_dev = 0; /* earlier 0xff80 */
-#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-#endif
+	{
+	    status_dead = NO;
+	    if (tp_sense(~(TP_ST1|TP_ILL)) != TE_OK)
+	    {
+		tpqputs(TPQD_ALWAYS, "open: tp_sense() failed\n");
+		status_dead = YES;	/* try reset next time */
 		return -EIO;
+	    }
 	}
-
+    }
+    
+    /* things should be ok, once we get here */
+    
+
+    /* set density: only allowed when TP_BOM status bit is set,
+     * so we must have done a rewind by now. If not, just skip over.
+     * Only give set density command when minor bits have changed.
+     */
+    if (TP_DENS(current_tape_dev) == TP_DENS(dev) )
+    {
 	return 0;
+    }
+    
+    current_tape_dev = dev;
+    need_rewind = NO;
+    if (TP_HAVE_DENS)
+    {
+	dens = TP_DENS(dev);
+    }
+    
+    if (dens < sizeof(format_names)/sizeof(char *))
+    {
+	printk(TPQIC02_NAME ": format: %s%s\n", (dens!=0)? "QIC-" : "", format_names[dens]);
+    }
+    else
+    {
+	tpqputs(TPQD_REWIND, "Wait for retensioning...");
+    }
+    
+    switch (TP_DENS(dev))
+    {
+     case 0: /* Minor 0 is for drives without set-density support */
+	s = 0;
+	break;
+     case 1:
+	s = do_qic_cmd(QCMD_DENS_11, TIM_S);
+	break;
+     case 2:
+	s = do_qic_cmd(QCMD_DENS_24, TIM_S);
+	break;
+     case 3:
+	s = do_qic_cmd(QCMD_DENS_120, TIM_S);
+	break;
+     case 4:
+	s = do_qic_cmd(QCMD_DENS_150, TIM_S);
+	break;
+     case 5:
+	s = do_qic_cmd(QCMD_DENS_300, TIM_S);
+	break;
+     case 6:
+	s = do_qic_cmd(QCMD_DENS_600, TIM_S);
+	break;
+     default:  /* otherwise do a retension before anything else */
+	s = do_qic_cmd(QCMD_RETEN, TIM_R);
+    }
+    if (s != 0)
+    {
+	status_dead = YES;	/* force reset */
+	current_tape_dev = 0; /* earlier 0xff80 */
+	return -EIO;
+    }
+    
+    return 0;
 } /* qic02_tape_open */
 
 
 static void qic02_tape_release(struct inode * inode, struct file * filp)
 {
-	kdev_t dev = inode->i_rdev;
-
-	if (TP_DIAGS(dev))
-		printk("qic02_tape_release: dev=%s\n",
-		       kdevname(dev));
-
-	if (status_zombie==YES)		/* don't rewind in zombie mode */
-#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-#endif
-		return;
+    kdev_t dev = inode->i_rdev;
 
+    if (TP_DIAGS(dev))
+    {
+	printk("qic02_tape_release: dev=%s\n",  kdevname(dev));
+    }
+    
+    if (status_zombie==NO)		/* don't rewind in zombie mode */
+    {
 	/* Terminate any pending write cycle. Terminating the read-cycle
 	 * is delayed until it is required to do so for a new command.
 	 */
 	terminate_write(-1);
-
+	
 	if (status_dead==YES)
-		tpqputs(TPQD_ALWAYS, "release: device dead!?");
-
- 	/* Rewind only if minor number requires it AND 
+	{
+	    tpqputs(TPQD_ALWAYS, "release: device dead!?");
+	}
+	
+	/* Rewind only if minor number requires it AND 
 	 * read/writes have been done. ************* IS THIS CORRECT??????????
 	 */
-	if ((TP_REWCLOSE(dev)) && (status_bytes_rd | status_bytes_wr)) {
-		tpqputs(TPQD_REWIND, "release: Doing rewind...");
-		(void) do_qic_cmd(QCMD_REWIND, TIM_R);
+	if ((TP_REWCLOSE(dev)) && (status_bytes_rd | status_bytes_wr))
+	{
+	    tpqputs(TPQD_REWIND, "release: Doing rewind...");
+	    (void) do_qic_cmd(QCMD_REWIND, TIM_R);
 	}
+    }
 #ifdef MODULE
-	MOD_DEC_USE_COUNT;
+    MOD_DEC_USE_COUNT;
 #endif
-	return;
+    return;
 } /* qic02_tape_release */
 
 
 #ifdef CONFIG_QIC02_DYNCONF
 /* Set masks etc. based on the interface card type. */
-int update_ifc_masks(int ifc)
+static int update_ifc_masks(int ifc)
 {
-	QIC02_TAPE_IFC = ifc;
-
-	if ((QIC02_TAPE_IFC == WANGTEK) || (QIC02_TAPE_IFC == EVEREX)) {
-		QIC02_STAT_PORT = QIC02_TAPE_PORT;
-		QIC02_CTL_PORT = QIC02_TAPE_PORT;
-		QIC02_CMD_PORT = QIC02_TAPE_PORT+1;
-		QIC02_DATA_PORT = QIC02_TAPE_PORT+1;
-		QIC02_STAT_READY = WT_QIC02_STAT_READY;
-		QIC02_STAT_EXCEPTION = WT_QIC02_STAT_EXCEPTION;
-		QIC02_STAT_MASK = WT_QIC02_STAT_MASK;
-
-		QIC02_STAT_RESETMASK = WT_QIC02_STAT_RESETMASK;
-		QIC02_STAT_RESETVAL = WT_QIC02_STAT_RESETVAL;
-
-		QIC02_CTL_RESET = WT_QIC02_CTL_RESET;
-		QIC02_CTL_REQUEST = WT_QIC02_CTL_REQUEST;
- 
-		if (QIC02_TAPE_DMA == 3)
-			WT_CTL_DMA = WT_CTL_DMA3;
-		else if (QIC02_TAPE_DMA == 1)
-			WT_CTL_DMA = WT_CTL_DMA1;
-		else {
-			tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
-			return -EIO;
-		} 
+    QIC02_TAPE_IFC = ifc;
 
-		if (QIC02_TAPE_IFC == EVEREX) {
-			/* Everex is a special case for Wangtek (actually
-			 * it's the other way 'round, but I saw Wangtek first)
-			 */
-			if (QIC02_TAPE_DMA==3)
-				WT_CTL_DMA = WT_CTL_DMA1;
-			/* Fixup the kernel copy of the IFC type to that
-			 * we don't have to distinguish between Wangtek and
-			 * and Everex at runtime.
-			 */
-			QIC02_TAPE_IFC = WANGTEK;
-		}
-	} else if (QIC02_TAPE_IFC == ARCHIVE) {
-		QIC02_STAT_PORT = QIC02_TAPE_PORT+1;
-		QIC02_CTL_PORT = QIC02_TAPE_PORT+1;
-		QIC02_CMD_PORT = QIC02_TAPE_PORT;
-		QIC02_DATA_PORT = QIC02_TAPE_PORT;
-		QIC02_STAT_READY = AR_QIC02_STAT_READY;
-		QIC02_STAT_EXCEPTION  = AR_QIC02_STAT_EXCEPTION;
-		QIC02_STAT_MASK = AR_QIC02_STAT_MASK;
-
-		QIC02_STAT_RESETMASK = AR_QIC02_STAT_RESETMASK;
-		QIC02_STAT_RESETVAL = AR_QIC02_STAT_RESETVAL;
-
-		QIC02_CTL_RESET = AR_QIC02_CTL_RESET;
-		QIC02_CTL_REQUEST = AR_QIC02_CTL_REQUEST;
- 
-		if (QIC02_TAPE_DMA > 3) {
-			tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
-			return -EIO;
-		} 
-	} else if (QIC02_TAPE_IFC == MOUNTAIN) {
-		QIC02_STAT_PORT = QIC02_TAPE_PORT+1;
-		QIC02_CTL_PORT = QIC02_TAPE_PORT+1;
-		QIC02_CMD_PORT = QIC02_TAPE_PORT;
-		QIC02_DATA_PORT = QIC02_TAPE_PORT;
-
-		QIC02_STAT_READY = MTN_QIC02_STAT_READY;
-		QIC02_STAT_EXCEPTION  = MTN_QIC02_STAT_EXCEPTION;
-		QIC02_STAT_MASK = MTN_QIC02_STAT_MASK;
-
-		QIC02_STAT_RESETMASK = MTN_QIC02_STAT_RESETMASK;
-		QIC02_STAT_RESETVAL = MTN_QIC02_STAT_RESETVAL;
-
-		QIC02_CTL_RESET = MTN_QIC02_CTL_RESET;
-		QIC02_CTL_REQUEST = MTN_QIC02_CTL_REQUEST;
+    if ((QIC02_TAPE_IFC == WANGTEK) || (QIC02_TAPE_IFC == EVEREX))
+    {
+	QIC02_STAT_PORT = QIC02_TAPE_PORT;
+	QIC02_CTL_PORT = QIC02_TAPE_PORT;
+	QIC02_CMD_PORT = QIC02_TAPE_PORT+1;
+	QIC02_DATA_PORT = QIC02_TAPE_PORT+1;
+	QIC02_STAT_READY = WT_QIC02_STAT_READY;
+	QIC02_STAT_EXCEPTION = WT_QIC02_STAT_EXCEPTION;
+	QIC02_STAT_MASK = WT_QIC02_STAT_MASK;
+	
+	QIC02_STAT_RESETMASK = WT_QIC02_STAT_RESETMASK;
+	QIC02_STAT_RESETVAL = WT_QIC02_STAT_RESETVAL;
+	
+	QIC02_CTL_RESET = WT_QIC02_CTL_RESET;
+	QIC02_CTL_REQUEST = WT_QIC02_CTL_REQUEST;
  
-		if (QIC02_TAPE_DMA > 3) {
-			tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
-			return -EIO;
-		} 
-	} else {
-		tpqputs(TPQD_ALWAYS, "Invalid interface type");
-		return -ENXIO;
+	if (QIC02_TAPE_DMA == 3)
+	{
+	    WT_CTL_DMA = WT_CTL_DMA3;
 	}
-	return 0;
-} /* update_ifc-masks */
+	else if (QIC02_TAPE_DMA == 1)
+	{
+	    WT_CTL_DMA = WT_CTL_DMA1;
+	}
+	else
+	{
+	    tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
+	    return -EIO;
+	} 
+
+	if (QIC02_TAPE_IFC == EVEREX)
+	{
+	    /* Everex is a special case for Wangtek (actually
+	     * it's the other way 'round, but I saw Wangtek first)
+	     */
+	    if (QIC02_TAPE_DMA==3)
+	    {
+		WT_CTL_DMA = WT_CTL_DMA1;
+	    }
+	    
+	    /* Fixup the kernel copy of the IFC type to that
+	     * we don't have to distinguish between Wangtek and
+	     * and Everex at runtime.
+	     */
+	    QIC02_TAPE_IFC = WANGTEK;
+	}
+    }
+    else if (QIC02_TAPE_IFC == ARCHIVE)
+    {
+	QIC02_STAT_PORT = QIC02_TAPE_PORT+1;
+	QIC02_CTL_PORT = QIC02_TAPE_PORT+1;
+	QIC02_CMD_PORT = QIC02_TAPE_PORT;
+	QIC02_DATA_PORT = QIC02_TAPE_PORT;
+	QIC02_STAT_READY = AR_QIC02_STAT_READY;
+	QIC02_STAT_EXCEPTION  = AR_QIC02_STAT_EXCEPTION;
+	QIC02_STAT_MASK = AR_QIC02_STAT_MASK;
+	
+	QIC02_STAT_RESETMASK = AR_QIC02_STAT_RESETMASK;
+	QIC02_STAT_RESETVAL = AR_QIC02_STAT_RESETVAL;
+	
+	QIC02_CTL_RESET = AR_QIC02_CTL_RESET;
+	QIC02_CTL_REQUEST = AR_QIC02_CTL_REQUEST;
+	
+	if (QIC02_TAPE_DMA > 3)
+	{
+	    tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
+	    return -EIO;
+	} 
+    }
+    else if (QIC02_TAPE_IFC == MOUNTAIN)
+    {
+	QIC02_STAT_PORT = QIC02_TAPE_PORT+1;
+	QIC02_CTL_PORT = QIC02_TAPE_PORT+1;
+	QIC02_CMD_PORT = QIC02_TAPE_PORT;
+	QIC02_DATA_PORT = QIC02_TAPE_PORT;
+	
+	QIC02_STAT_READY = MTN_QIC02_STAT_READY;
+	QIC02_STAT_EXCEPTION  = MTN_QIC02_STAT_EXCEPTION;
+	QIC02_STAT_MASK = MTN_QIC02_STAT_MASK;
+	
+	QIC02_STAT_RESETMASK = MTN_QIC02_STAT_RESETMASK;
+	QIC02_STAT_RESETVAL = MTN_QIC02_STAT_RESETVAL;
+	
+	QIC02_CTL_RESET = MTN_QIC02_CTL_RESET;
+	QIC02_CTL_REQUEST = MTN_QIC02_CTL_REQUEST;
+	
+	if (QIC02_TAPE_DMA > 3)
+	{
+	    tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
+	    return -EIO;
+	} 
+    }
+    else
+    {
+	tpqputs(TPQD_ALWAYS, "Invalid interface type");
+	return -ENXIO;
+    }
+    return qic02_get_resources();
+} /* update_ifc_masks */
 #endif
 
 
@@ -2596,209 +2536,207 @@
 static int qic02_tape_ioctl(struct inode * inode, struct file * filp, 
 		     unsigned int iocmd, unsigned long ioarg)
 {
-	int error;
-	int dev_maj = MAJOR(inode->i_rdev);
-	int c;
-	struct mtop operation;
-	char *stp, *argp;
-	unsigned char blk_addr[6];
-	struct mtpos ioctl_tell;
+    int error;
+    int dev_maj = MAJOR(inode->i_rdev);
+    int c;
+    struct mtop operation;
+    unsigned char blk_addr[6];
+    struct mtpos ioctl_tell;
+    
+
+    if (TP_DIAGS(current_tape_dev))
+    {
+	printk(TPQIC02_NAME ": ioctl(%4x, %4x, %4lx)\n", dev_maj, iocmd, ioarg);
+    }
+    
+    if (!inode || !ioarg)
+    {
+	return -EINVAL;
+    }
+    
+    /* check iocmd first */
+
+    if (dev_maj != QIC02_TAPE_MAJOR)
+    {
+	printk(TPQIC02_NAME ": Oops! Wrong device?\n");
+	/* A panic() would be appropriate here */
+	return -ENODEV;
+    }
 
+    c = _IOC_NR(iocmd);
 
-	if (TP_DIAGS(current_tape_dev))
-		printk(TPQIC02_NAME ": ioctl(%4x, %4x, %4lx)\n", dev_maj, iocmd, ioarg);
+#ifdef CONFIG_QIC02_DYNCONF
+    if (c == _IOC_NR(MTIOCGETCONFIG))
+    {
+	CHECK_IOC_SIZE(mtconfiginfo);
 
-	if (!inode || !ioarg)
-		return -EINVAL;
+	if (copy_to_user((char *) ioarg, (char *) &qic02_tape_dynconf, sizeof(qic02_tape_dynconf)))
+	{
+	    return -EFAULT;
+	}
+	return 0;
 
-	/* check iocmd first */
+    }
+    else if (c == _IOC_NR(MTIOCSETCONFIG))
+    {
+	/* One should always do a MTIOCGETCONFIG first, then update
+	 * user-settings, then write back with MTIOCSETCONFIG.
+	 * The qic02conf program should re-open() the device before actual
+	 * use, to make sure everything is initialized.
+	 */
+	
+	CHECK_IOC_SIZE(mtconfiginfo);
+	
+	if (!suser())
+	{
+	    return -EPERM;
+	}
+	
+	if ((doing_read!=NO) || (doing_write!=NO))
+	{
+	    return -EBUSY;
+	}
+	
+	if (status_zombie==NO)
+	{
+	    qic02_release_resources();	/* and go zombie */
+	}
+	
+	/* copy struct from user space to kernel space */
+	if (copy_from_user((char *) &qic02_tape_dynconf, (char *) ioarg, sizeof(qic02_tape_dynconf)))
+	{
+	    return -EFAULT;
+	}
+	return update_ifc_masks(qic02_tape_dynconf.ifc_type);
+    }
+    if (status_zombie==YES)
+    {
+	tpqputs(TPQD_ALWAYS, "Configs not set");
+	return -ENXIO;
+    }
+#endif
+    if (c == _IOC_NR(MTIOCTOP))
+    {
+	CHECK_IOC_SIZE(mtop);
 
-	if (dev_maj != QIC02_TAPE_MAJOR) {
-		printk(TPQIC02_NAME ": Oops! Wrong device?\n");
-		/* A panic() would be appropriate here */
-		return -ENODEV;
-	}
-
-	c = iocmd & IOCCMD_MASK;
-
-#ifdef DDIOCSDBG
-	/* Check for DDI Debug Control, contributed by FvK, edited by HHB. */
-	if (c == DDIOCSDBG) {
-		if (!suser())
-			return -EPERM;
-		error = get_user(c, (int *) ioarg);
-		if (error)
-			return error;
-		if (c==0) {
-			QIC02_TAPE_DEBUG = 0;
-			return 0;
-		}
-		if ((c>=1) && (c<=32)) {
-			QIC02_TAPE_DEBUG |= (1 << (c-1));
-			return 0;
-		}
-		if (c >= 128) {
-			QIC02_TAPE_DEBUG &= ~(1 << (c - 128));
-			return 0;
-		}
-		return -EINVAL;
+	/* copy mtop struct from user space to kernel space */
+	if (copy_from_user((char *) &operation, (char *) ioarg, sizeof(operation)))
+	{
+	    return -EFAULT;
 	}
-#endif
 
-#ifdef CONFIG_QIC02_DYNCONF
-	if (c == (MTIOCGETCONFIG & IOCCMD_MASK)) {
-		if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtconfiginfo)) {
-			tpqputs(TPQD_ALWAYS, "sizeof(struct mtconfiginfo) does not match!");
-			return -EFAULT;
-		}
-
-		/* check for valid user address and copy current settings to user space */
-		stp = (char *) &qic02_tape_dynconf;
-		argp = (char *) ioarg;
-		if (copy_to_user(stp, argp, sizeof(qic02_tape_dynconf)))
-			return -EFAULT;
-		return 0;
-
-	} else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) {
-		static int qic02_get_resources(void), qic02_release_resources(void);
-
-		/* One should always do a MTIOCGETCONFIG first, then update
-		 * user-settings, then write back with MTIOCSETCONFIG.
-		 * Re-open() the device before actual use to make sure
-		 * everything is initialized.
-		 */
-		if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtconfiginfo)) {
-			tpqputs(TPQD_ALWAYS, "sizeof(struct mtconfiginfo) does not match!");
-			return -EFAULT;
-		}
-		if (!suser())
-			return -EPERM;
-		if ((doing_read!=NO) || (doing_write!=NO))
-			return -EBUSY;
-
-		/* copy struct from user space to kernel space */
-		stp = (char *) &qic02_tape_dynconf;
-		argp = (char *) ioarg;
-		if (copy_from_user(stp, argp, sizeof(qic02_tape_dynconf)))
-			return -EFAULT;
-		if (status_zombie==NO)
-			qic02_release_resources();	/* and go zombie */
-		if (update_ifc_masks(qic02_tape_dynconf.ifc_type))
-			return -EIO;
-		if (qic02_get_resources())
-			return -ENXIO;
-		return 0;
+	/* ---note: mt_count is signed, negative seeks must be
+	 * ---	    translated to seeks in opposite direction!
+	 * (only needed for Sun-programs, I think.)
+	 */
+	/* ---note: MTFSF with count 0 should position the
+	 * ---	    tape at the beginning of the current file.
+	 */
 
+	if (TP_DIAGS(current_tape_dev))
+	{
+	    printk("OP op=%4x, count=%4x\n", operation.mt_op, operation.mt_count);
 	}
-	if (status_zombie==YES) {
-		tpqputs(TPQD_ALWAYS, "Configs not set");
-		return -ENXIO;
+	
+	if (operation.mt_count < 0)
+	{
+	    tpqputs(TPQD_ALWAYS, "Warning: negative mt_count ignored");
 	}
-#endif
-	if (c == (MTIOCTOP & IOCCMD_MASK)) {
-
-		/* Compare expected struct size and actual struct size. This
-		 * is useful to catch programs compiled with old #includes.
-		 */
-		if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtop)) {
-			tpqputs(TPQD_ALWAYS, "sizeof(struct mtop) does not match!");
-			return -EFAULT;
+	
+	ioctl_status.mt_resid = operation.mt_count;
+	if (operation.mt_op == MTSEEK)
+	{
+	    if (!TP_HAVE_SEEK)
+	    {
+		return -ENOTTY;
+	    }
+	    
+	    seek_addr_buf[0] = (operation.mt_count>>16)&0xff;
+	    seek_addr_buf[1] = (operation.mt_count>>8)&0xff;
+	    seek_addr_buf[2] = (operation.mt_count)&0xff;
+	    if (operation.mt_count>>24)
+	    {
+		return -EINVAL;
+	    }
+	    if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
+	    {
+		return error;
+	    }
+	    
+	    ioctl_status.mt_resid = 0;
+	}
+	else
+	{
+	    while (operation.mt_count > 0)
+	    {
+		operation.mt_count--;
+		if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
+		{
+		    return error;
 		}
-
-		/* copy mtop struct from user space to kernel space */
-		stp = (char *) &operation;
-		argp = (char *) ioarg;
-		if (copy_from_user(stp, argp, sizeof(operation)))
-			return -EFAULT;
-
-		/* ---note: mt_count is signed, negative seeks must be
-		 * ---	    translated to seeks in opposite direction!
-		 * (only needed for Sun-programs, I think.)
-		 */
-		/* ---note: MTFSF with count 0 should position the
-		 * ---	    tape at the beginning of the current file.
-		 */
-
-		if (TP_DIAGS(current_tape_dev))
-			printk("OP op=%4x, count=%4x\n", operation.mt_op, operation.mt_count);
-
-		if (operation.mt_count < 0)
-			tpqputs(TPQD_ALWAYS, "Warning: negative mt_count ignored");
-
+		
 		ioctl_status.mt_resid = operation.mt_count;
-		if (operation.mt_op == MTSEEK) {
-			if (!TP_HAVE_SEEK)
-				return -ENOTTY;
-			seek_addr_buf[0] = (operation.mt_count>>16)&0xff;
-			seek_addr_buf[1] = (operation.mt_count>>8)&0xff;
-			seek_addr_buf[2] = (operation.mt_count)&0xff;
-			if (operation.mt_count>>24)
-				return -EINVAL;
-			if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
-				return error;
-			ioctl_status.mt_resid = 0;
-		} else {
-			while (operation.mt_count > 0) {
-				operation.mt_count--;
-				if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
-					return error;
-				ioctl_status.mt_resid = operation.mt_count;
-			}
-		}
-		return 0;
-
-	} else if (c == (MTIOCGET & IOCCMD_MASK)) {
-		if (TP_DIAGS(current_tape_dev))
-			printk("GET ");
-
-		/* compare expected struct size and actual struct size */
-		if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtget)) {
-			tpqputs(TPQD_ALWAYS, "sizeof(struct mtget) does not match!");
-			return -EFAULT;
-		}
-
-		/* It appears (gmt(1)) that it is normal behaviour to
-		 * first set the status with MTNOP, and then to read
-		 * it out with MTIOCGET
-		 */
-
-		/* copy results to user space */
-		stp = (char *) &ioctl_status;
-		argp = (char *) ioarg;
-		if (copy_to_user(stp, argp, sizeof(ioctl_status)))
-			return -EFAULT;
-		return 0;
-
-
-	} else if (TP_HAVE_TELL && (c == (MTIOCPOS & IOCCMD_MASK))) {
-		if (TP_DIAGS(current_tape_dev))
-			printk("POS ");
-
-		/* compare expected struct size and actual struct size */
-		if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtpos)) {
-			tpqputs(TPQD_ALWAYS, "sizeof(struct mtpos) does not match!");
-			return -EFAULT;
-		}
-
-		tpqputs(TPQD_IOCTLS, "MTTELL reading block address");
-		if ((doing_read==YES) || (doing_write==YES))
-			finish_rw(AR_QCMDV_TELL_BLK);
+	    }
+	}
+	return 0;
+	
+    }
+    else if (c == _IOC_NR(MTIOCGET))
+    {
+	if (TP_DIAGS(current_tape_dev))
+	{
+	    printk("GET ");
+	}
+	
+	CHECK_IOC_SIZE(mtget);
 
-		c = rdstatus((char *) blk_addr, sizeof(blk_addr), AR_QCMDV_TELL_BLK);
-		if (c!=TE_OK)
-			return -EIO;
+	/* It appears (gmt(1)) that it is normal behaviour to
+	 * first set the status with MTNOP, and then to read
+	 * it out with MTIOCGET
+	 */
 
-		ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
+	/* copy results to user space */
+	if (copy_to_user((char *) &ioctl_status, (char *) ioarg, sizeof(ioctl_status)))
+	{
+	    return -EFAULT;
+	}	
+	return 0;
+    }
+    else if (TP_HAVE_TELL && (c == _IOC_NR(MTIOCPOS)))
+    {
+	if (TP_DIAGS(current_tape_dev))
+	{
+	    printk("POS ");
+	}
+	
+	CHECK_IOC_SIZE(mtpos);
+	
+	tpqputs(TPQD_IOCTLS, "MTTELL reading block address");
+	if ((doing_read==YES) || (doing_write==YES))
+	{
+	    finish_rw(AR_QCMDV_TELL_BLK);
+	}
+	
+	c = rdstatus((char *) blk_addr, sizeof(blk_addr), AR_QCMDV_TELL_BLK);
+	if (c!=TE_OK)
+	{
+	    return -EIO;
+	}
+	
+	ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
 
-		/* copy results to user space */
-		stp = (char *) &ioctl_tell;
-		argp = (char *) ioarg;
-		if (copy_to_user(stp, argp, sizeof(ioctl_status)))
-			return -EFAULT;
-		return 0;
+	/* copy results to user space */
+	if (copy_to_user((char *) ioarg, (char *) &ioctl_tell, sizeof(ioctl_tell)))
+	{
+	    return -EFAULT;
+	}
+	return 0;
 
-	} else
-		return -ENOTTY;	/* Other cmds not supported. */
+    }
+    else
+    {
+	return -ENOTTY;	/* Other cmds not supported. */
+    }
 } /* qic02_tape_ioctl */
 
 
@@ -2820,215 +2758,229 @@
 	NULL				/* revalidate */
 };
 
-/* align `a' at `size' bytes. `size' must be a power of 2 */
-static inline unsigned long const align_buffer(unsigned long a, unsigned size)
-{
-	if (a & (size-1))			/* if not aligned */
-		return (a | (size-1)) + 1;
-	else					/* else is aligned */
-		return a;
-}
 
+/* Why is this not is one place? */
+/* Pure 2^n version of get_order */
+static inline int __get_order(unsigned long size)
+{
+    int order;
+
+    size = (size-1) >> (PAGE_SHIFT-1);
+    order = -1;
+    do
+    {
+	size >>= 1;
+	order++;
+    } while (size);
+    return order;
+}
 
 
 static void qic02_release_resources(void)
 {
-	free_irq(QIC02_TAPE_IRQ, NULL);
-	free_dma(QIC02_TAPE_DMA);
-	status_zombie = YES;
+    free_irq(QIC02_TAPE_IRQ, NULL);
+    free_dma(QIC02_TAPE_DMA);
+    release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
+    if (buffaddr)
+    {
+	free_pages(buffaddr, __get_order(TPQBUF_SIZE));
+    }
+    buffaddr = 0; /* Better to cause a panic than overwite someone else */
+    status_zombie = YES;
 } /* qic02_release_resources */
 
 
-
-
 static int qic02_get_resources(void)
 {
-	/* First perform some checks. If one of them fails,
-	 * the tape driver will not be registered to the system.
-	 */
-	if (QIC02_TAPE_IRQ>16) {
-		tpqputs(TPQD_ALWAYS, "Bogus interrupt number.");
-		return -1;
-	}
-
-	/* for DYNCONF, allocating DMA & IRQ should not be done until 
-         * the config parameters have been set using MTSETCONFIG.
-	 */
-
-	/* get IRQ */
-	if (request_irq(QIC02_TAPE_IRQ, qic02_tape_interrupt, SA_INTERRUPT, "QIC-02", NULL)) {
-		printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n",
-			QIC02_TAPE_IRQ);
-		status_zombie = YES;
-		return -1;
-	}
-
-	/* After IRQ, allocate DMA channel */
-	if (request_dma(QIC02_TAPE_DMA,"QIC-02")) {
-		printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n",
-			QIC02_TAPE_DMA);
-		free_irq(QIC02_TAPE_IRQ, NULL);
-		status_zombie = YES;
-		return -1;
-	}
-
-	printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
-		QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
-		((QIC02_TAPE_IFC==ARCHIVE) || (QIC02_TAPE_IFC==MOUNTAIN))?
-			QIC02_CMD_PORT : QIC02_STAT_PORT,
-		(QIC02_TAPE_IFC==MOUNTAIN)? "Mountain" :
-			((QIC02_TAPE_IFC==ARCHIVE)? "Archive" : "Wangtek"));
+    /* First perform some checks. If one of them fails,
+     * the tape driver will not be registered to the system.
+     */
+    if (QIC02_TAPE_IRQ>16)
+    {
+	tpqputs(TPQD_ALWAYS, "Bogus interrupt number.");
+	return -ENXIO;
+    }
+
+    /* for DYNCONF, allocating IO, DMA and IRQ should not be done until 
+     * the config parameters have been set using MTSETCONFIG.
+     */
+
+    if (check_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE))
+    {
+	printk(TPQIC02_NAME ": IO space at 0x%x [%d ports] already reserved\n",
+	       QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
+	return -ENXIO;
+    }
+
+    /* get IRQ */
+    if (request_irq(QIC02_TAPE_IRQ, qic02_tape_interrupt, SA_INTERRUPT, "QIC-02", NULL))
+    {
+	printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n",
+	       QIC02_TAPE_IRQ);
+	return -EBUSY;
+    }
+
+    /* After IRQ, allocate DMA channel */
+    if (request_dma(QIC02_TAPE_DMA,"QIC-02"))
+    {
+	printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n",
+	       QIC02_TAPE_DMA);
+	free_irq(QIC02_TAPE_IRQ, NULL);
+	return -EBUSY;
+    }
 
-	if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) {
-		/* No drive detected, so vanish */
-		tpqputs(TPQD_ALWAYS, "No drive detected -- releasing irq and dma.");
-		status_dead = YES;
-		qic02_release_resources();
-		return -1;
-	}
+    /* Grab the IO region. We already made sure it's available. */
+    request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, TPQIC02_NAME);
+    
+    /* Setup the page-address for the dma transfer. */
+
+    /*** TODO: does _get_dma_pages() really return the physical address?? ****/
+    buffaddr = __get_dma_pages(GFP_KERNEL,__get_order(TPQBUF_SIZE));
+    
+    if (!buffaddr)
+    {
+	qic02_release_resources();
+	return -EBUSY; /* Not ideal, EAGAIN perhaps? */
+    }
+    
+    memset( (void*) buffaddr, 0, TPQBUF_SIZE );
+    
+    printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
+	   QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
+	   ((QIC02_TAPE_IFC==ARCHIVE) || (QIC02_TAPE_IFC==MOUNTAIN))?
+	   QIC02_CMD_PORT : QIC02_STAT_PORT,
+	   (QIC02_TAPE_IFC==MOUNTAIN)? "Mountain" :
+	   ((QIC02_TAPE_IFC==ARCHIVE)? "Archive" : "Wangtek"));
+    
+    if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK)
+    {
+	/* No drive detected, so vanish */
+	tpqputs(TPQD_ALWAYS, "No drive detected -- releasing IO/IRQ/DMA.");
+	status_dead = YES;
+	qic02_release_resources();
+	return -EIO;
+    }
 
-	/* All should be ok now */
-	status_zombie = NO;
-	return 0;
+    /* All should be ok now */
+    status_zombie = NO;
+    return 0;
 } /* qic02_get_resources */
 
-
+#ifdef MODULE
+static
+#endif
 int qic02_tape_init(void)
-	/* Shouldn't this be a caddr_t ? */
 {
+    if (TPSTATSIZE != 6)
+    {
+	printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
+	return -ENODEV;
+    }
+    if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000))
+    {
+	printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
+	return -ENODEV;
+    }
 
-	if (TPSTATSIZE != 6) {
-		printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
-		return -ENODEV;
-	}
-	if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000)) {
-		printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
-		return -ENODEV;
-	}
-
-	QIC02_TAPE_DEBUG = TPQD_DEFAULT_FLAGS;
-
-	current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0);
+    current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0);
 
 #ifndef CONFIG_QIC02_DYNCONF
-	printk(TPQIC02_NAME ": IRQ %d, DMA %d, IO 0x%x, IFC %s, %s, %s\n",
-		 QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
+    printk(TPQIC02_NAME ": IRQ %d, DMA %d, IO 0x%x, IFC %s, %s, %s\n",
+	   QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
 # if QIC02_TAPE_IFC == WANGTEK
-		 QIC02_STAT_PORT, "Wangtek",
+	   QIC02_STAT_PORT, "Wangtek",
 # elif QIC02_TAPE_IFC == ARCHIVE
-		 QIC02_CMD_PORT, "Archive",
+	   QIC02_CMD_PORT, "Archive",
 # elif QIC02_TAPE_IFC == MOUNTAIN
-		 QIC02_CMD_PORT, "Mountain",
+	   QIC02_CMD_PORT, "Mountain",
 # else
 #  error
 # endif
-		 rcs_revision, rcs_date);
-	if (qic02_get_resources())
-		return -ENODEV;
+	   rcs_revision, rcs_date);
+    if (qic02_get_resources())
+    {
+	return -ENODEV;
+    }
 #else
-	printk(TPQIC02_NAME ": Runtime config, %s, %s\n", 
-		 rcs_revision, rcs_date);
-	
-	QIC02_TAPE_IRQ = BOGUS_IRQ;	/* invalid value */
+    printk(TPQIC02_NAME ": Runtime config, %s, %s\n", 
+	   rcs_revision, rcs_date);
 #endif
-
-	printk(TPQIC02_NAME ": DMA buffers: %u blocks", NR_BLK_BUF);
-
-	/* 
-	 * Setup the page-address for the dma transfer.
-	 */
-#ifdef MODULE
-        qic02_tape_buf = kmalloc(TPQBUF_SIZE+TAPE_BLKSIZE, GFP_DMA);
-        if (qic02_tape_buf == NULL) {
+    printk(TPQIC02_NAME ": DMA buffers: %u blocks\n", NR_BLK_BUF);
+    /* If we got this far, install driver functions */
+    if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops))
+    {
+	printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
 #ifndef CONFIG_QIC02_DYNCONF
-        /*
-         * irq and dma were requested by qic_get_resources, so
-         * relase them only when _not_ using DYNCONF
-         */
-		qic02_release_resources();
-#endif
-		return -ENODEV;
-       }
-       buffaddr = align_buffer(virt_to_bus((unsigned long *)qic02_tape_buf),
-                               TAPE_BLKSIZE);
-       printk(", at address 0x%lx (0x%lx)\n", buffaddr,
-              virt_to_bus((unsigned long *)qic02_tape_buf));
-#else /* no MODULE */
-	buffaddr = align_buffer(virt_to_bus(qic02_tape_buf), TAPE_BLKSIZE);
-	printk(", at address 0x%lx (0x%lx)\n", buffaddr, (unsigned long) &qic02_tape_buf);
-#endif /* MODULE */
-
-
-#ifndef CONFIG_MAX_16M
-	if (buffaddr+TPQBUF_SIZE>=0x1000000) {
-		printk(TPQIC02_NAME ": DMA buffer *must* be in lower 16MB\n");
-#ifdef MODULE
-		qic02_release_resources();
-                kfree(qic02_tape_buf);
-#endif
-
-		return -ENODEV;
-	}
-#endif
-
-	/* If we got this far, install driver functions */
-	if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops)) {
-		printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
-#ifndef CONFIG_QIC02_DYNCONF
-		qic02_release_resources();
+	qic02_release_resources();
 #endif
-		return -ENODEV;
-	}
-
-	/* prepare timer */
-	TIMEROFF;
-	timer_table[QIC02_TAPE_TIMER].expires = 0;
-	timer_table[QIC02_TAPE_TIMER].fn = qic02_tape_times_out;
+	return -ENODEV;
+    }
 
+    /* prepare timer */
+    TIMEROFF;
+    timer_table[QIC02_TAPE_TIMER].expires = 0;
+    timer_table[QIC02_TAPE_TIMER].fn = qic02_tape_times_out;
+    
 #ifndef CONFIG_QIC02_DYNCONF
-	if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) {
-		/* No drive detected, so vanish */
-		tpqputs(TPQD_ALWAYS, "No drive detected -- driver going on vacation...");
-		unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
-		qic02_release_resources();
-		return -ENODEV;
-	} else {
-		if (is_exception()) {
-			tpqputs(TPQD_ALWAYS, "exception detected\n");
-			(void) tp_sense(TP_WRP|TP_POR|TP_CNI);
-		}
+    if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK)
+    {
+	/* No drive detected, so vanish */
+	tpqputs(TPQD_ALWAYS, "No drive detected -- driver going on vacation...");
+	qic02_release_resources();
+	status_dead = YES;
+	return -ENODEV;
+    }
+    else
+    {
+	if (is_exception())
+	{
+	    tpqputs(TPQD_ALWAYS, "exception detected\n");
+	    (void) tp_sense(TP_WRP|TP_POR|TP_CNI);
 	}
+    }
 #endif
 
-	/* initialize generic status for ioctl requests */
-
-	ioctl_status.mt_type	= QIC02_TAPE_DRIVE;	/* MT_IS* id nr */
-
-	ioctl_status.mt_resid	= 0;	/* ---residual count */
-	ioctl_status.mt_gstat	= 0;	/* ---generic status */
-	ioctl_status.mt_erreg	= 0;	/* not used */
-	ioctl_status.mt_fileno	= 0;	/* number of current file on tape */
-	ioctl_status.mt_blkno	= 0;	/* number of current (logical) block */
+    /* initialize generic status for ioctl requests */
+    
+    ioctl_status.mt_type	= QIC02_TAPE_DRIVE;	/* MT_IS* id nr */
+    
+    ioctl_status.mt_resid	= 0;	/* ---residual count */
+    ioctl_status.mt_gstat	= 0;	/* ---generic status */
+    ioctl_status.mt_erreg	= 0;	/* not used */
+    ioctl_status.mt_fileno	= 0;	/* number of current file on tape */
+    ioctl_status.mt_blkno	= 0;	/* number of current (logical) block */
 
-	return 0;
+    return 0;
 } /* qic02_tape_init */
 
 #ifdef MODULE
 
-int init_module(void) {
-	return qic02_tape_init();
-}
-
-void cleanup_module(void) {
-	unsigned long flags;
-       
-	save_flags(flags); 
-	cli(); 
-	unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME); 
+void cleanup_module(void)
+{
+    if (status_zombie == NO)
+    {
 	qic02_release_resources();
-	if (qic02_tape_buf) kfree(qic02_tape_buf); 
-	sti(); 
-	restore_flags(flags); 
+    }
+    unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
 }
 
-#endif /* MODULE */
+int init_module(void)
+{
+    int retval;
+    retval=qic02_tape_init();
+# ifdef CONFIG_QIC02_DYNCONF
+    /* This allows the dynamic config program to setup the card
+     * by presetting qic02_tape_dynconf via insmod
+     */
+    if (!retval && qic02_tape_dynconf.ifc_type)
+    {
+	retval=update_ifc_masks(qic02_tape_dynconf.ifc_type);
+	if (retval)
+	{
+	  cleanup_module();
+	}
+    }
+# endif
+    return retval;
+}
+#endif

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