📄 tpqic02.c
字号:
/* $Id: tpqic02.c,v 0.2.1.21 1993/06/18 19:04:33 root Exp root $ * * Driver for tape drive support for Linux-i386 0.99.12. * * Copyright (c) 1993 by H. H. Bergman. All rights reserved. * Current e-mail address: csg279@wing.rug.nl * [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.] * * Distribution of this program in executable form is only allowed if * all of the corresponding source files are made available through the same * medium at no extra cost. * * I will not accept any responsibility for damage caused directly or * indirectly by this program, or code derived from this program. * * Use this code at your own risk. Don't blame me if it destroys your data! * Make sure you have a backup before you try this code. * * This driver was partially inspired by the 'wt' driver in the 386BSD * source distribution, which carries the following copyright notice: * * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * You are not allowed to change this line nor the text above. * * $Log: tpqic02.c,v $ * 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. * * Revision 0.1 1992/05/26 01:16:31 root * Initial version. Copyright H. H. Bergman 1992 * *//* After the legalese, now the important bits: * * This is a driver for the Wangtek 5150 tape drive with * a QIC-02 controller for ISA-PC type computers. * Hopefully it will work with other QIC-02 tape drives as well. * * Make sure your setup matches the configuration parameters. * Also, be careful to avoid IO conflicts with other devices! */#include <linux/config.h>/* skip this driver if not required for this configuration */#if CONFIG_TAPE_QIC02/*#define TDEBUG*/#define REALLY_SLOW_IO /* it sure is ... */#include <linux/sched.h>#include <linux/timer.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/mtio.h>#include <linux/fcntl.h>#include <linux/delay.h>#include <linux/tpqic02.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include <asm/segment.h>/* check existence of required configuration parameters */#if !defined(TAPE_QIC02_PORT) || \ !defined(TAPE_QIC02_IRQ) || \ !defined(TAPE_QIC02_DMA)#error tape_qic02 configuration error#endif#define TPQIC_NAME "tpqic02"/* Linux outb() commands have (value,port) as parameters. * One might expect (port,value) instead, so beware! */static volatile int ctlbits = 0; /* control reg bits for tape interface */static struct wait_queue *tape_qic02_transfer = NULL; /* sync rw with interrupts */static volatile struct mtget ioctl_status; /* current generic status */static volatile struct tpstatus tperror; /* last drive status */static char rcs_revision[] = "$Revision: 0.2.1.21 $";static char rcs_date[] = "$Date: 1993/06/18 19:04:33 $";/* Flag bits for status and outstanding requests. * (Could all be put in one bit-field-struct.) * Some variables need `volatile' because they may be modified * by an interrupt. */static volatile flag status_dead = YES; /* device is legally dead until proven alive */static flag status_open = NO; /* in use or not */static volatile flag status_bytes_wr = NO; /* write FM at close or not */static volatile flag status_bytes_rd = NO; /* (rd|wr) used for rewinding */static volatile unsigned long status_cmd_pending = 0; /* cmd in progress */static volatile flag status_expect_int = NO; /* ready for interrupts */static volatile flag status_timer_on = NO; /* using time-out */static volatile int status_error = 0; /* int handler may detect error */static volatile flag status_eof_detected = NO; /* end of file */static volatile flag status_eom_detected = NO; /* end of recorded media */static volatile flag status_eot_detected = NO; /* end of tape */static volatile flag doing_read = NO;static volatile flag doing_write = NO;static volatile unsigned long dma_bytes_todo;static volatile unsigned long dma_bytes_done;static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */static flag need_rewind = YES;static dev_t current_tape_dev = QIC02_TAPE_MAJOR << 8;static int extra_blocks_left = BLOCKS_BEYOND_EW;/* return_*_eof: * NO: not at EOF, * YES: tell app EOF was reached (return 0). * * return_*_eof==YES && reported_*_eof==NO ==> * return current buffer, next time(s) return EOF. * * return_*_eof==YES && reported_*_eof==YES ==> * at EOF and application knows it, so we can * move on to the next file. * */static flag return_read_eof = NO; /* set to signal app EOF was reached */static flag return_write_eof = NO;static flag reported_read_eof = NO; /* set when we've done that */static flag reported_write_eof = NO;#ifdef TP_HAVE_SEEK/* This is for doing `mt seek <blocknr>' */static char seek_addr_buf[SEEK_BUF_SIZE];#endif/* In write mode, we have to write a File Mark after the last block written, * when the tape device is closed. Tape repositioning and reading in write * mode is allowed as long as no actual writing has been done. After writing * the File Mark, repositioning and reading are allowed again. */static int mode_access; /* access mode: READ or WRITE *//* 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 * access the user buffers. [The kernel buffer must reside in the lower * 1MBytes 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. */static volatile char tape_qic02_buf[TPQBUF_SIZE+TAPE_BLKSIZE];/* A really good compiler would be able to align this at 512 bytes... :-( */static unsigned long buffaddr; /* aligned physical address of buffer *//* This translates minor numbers to the corresponding recording format: */static char *format_names[] = { "not set", /* for dumb drives unable to handle format selection */ "11", /* extinct */ "24", "120", "150", "300", /* untested. */ "600" /* untested. */};/* `exception_list' is needed for exception status reporting. * Exceptions 1..14 are defined by QIC-02 rev F. * The drive status is matched sequentially to each entry, * ignoring irrelevant bits, until a match is found. If no * match is found, exception number 0 is used. (That should of * course never happen...) The original table was based on the * "Exception Status Summary" in QIC-02 rev F, but some changes * were required to make it work with real-world drives. * * Exception 1 (CNI) is changed to also cover status 0x00e0 (mask USL), * Exception 4 (EOM) is changed to also cover status 0x8288 (mask EOR), * Exception 11 (FIL) is changed to also cover status 0x0089 (mask EOM). * Exception 15 (EOR) is added for seek-to-end-of-data (catch EOR), * Exception 16 (BOM) is added for beginning-of-media (catch BOM). */static struct exception_list_type { short mask, code; char *msg;} exception_list[] = { {0, 0, "Unknown exception status code", /* extra: 0 */}, {~(TP_WRP|TP_USL), TP_ST0|TP_CNI, /* My Wangtek 5150EQ sometimes reports a status code * of 0x00e0, which is not a valid exception code, but * I think it should be recognized as "NO CARTRIDGE". */ "Cartridge not in place" /* 1 */}, {-1, TP_ST0|TP_CNI|TP_USL|TP_WRP, "Drive not online" /* 2 */}, {~(TP_ST1|TP_BOM), TP_ST0|TP_WRP, "Write protected cartridge" /* 3 */}, {~(TP_ST1|TP_EOR), TP_ST0|TP_EOM, "End of media" /* 4 */}, {~TP_WRP, TP_ST0|TP_UDA| TP_ST1|TP_BOM, "Read or Write abort. Rewind tape." /* 5 */}, {~TP_WRP, TP_ST0|TP_UDA, "Read error. Bad block transferred." /* 6 */}, {~TP_WRP, TP_ST0|TP_UDA|TP_BNL, "Read error. Filler block transferred." /* 7 */}, {~TP_WRP, TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT, "Read error. No data detected." /* 8 */}, {~TP_WRP, TP_ST0|TP_EOM|TP_UDA|TP_BNL |TP_ST1|TP_NDT, "Read error. No data detected. EOM." /* 9 */}, {~(TP_WRP|TP_MBD|TP_PAR|TP_EOR), TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT|TP_BOM, "Read error. No data detected. BOM." /* 10 */}, {~(TP_WRP|TP_EOM), TP_ST0|TP_FIL, /* Status 0x0089 (EOM & FM) is viewed as an FM, * because it can only happen during a read. * EOM is checked separately for an FM condition. */ "File mark detected" /* 11 */}, {~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_ILL, "Illegal command" /* 12 */}, {~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_POR, "Reset occurred" /* 13 */}, {~TP_WRP, TP_ST0|TP_FIL|TP_MBD, /* NOTE: ST1 not set! */ "Marginal block detected" /* 14 */}, {~(TP_ST0|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL |TP_NDT), TP_ST1|TP_EOR, /********** Is the extra TP_NDT really needed Eddy? **********/ "End of recorded media" /* extra: 15 */}, /* 15 is returned when SEEKEOD completes successfully */ {~(TP_WRP|TP_ST0), TP_ST1|TP_BOM, "Beginning of media" /* extra: 16 */}#ifdef CYPHER_BUG /* Perhaps the Cypher driver clears the TP_BOM bit after the * status has been read? The QIC-02 specs explicitly state that * the BOM bit should remain set as long as the tape is logically * at the beginning of the tape. */ ,{-1, TP_ST1, "Hmm, this must be Cypher drive... Aaargh" /* extra */}#endif};#define NR_OF_EXC (sizeof(exception_list)/sizeof(struct exception_list_type))static void tpqputs(char *s){ printk(TPQIC_NAME ": %s\n", s);} /* tpqputs *//* Perform byte order swapping for a 16-bit word. * * [FIXME] This should probably be in include/asm/ * ([FIXME] i486 can do this faster) */static inline void byte_swap_w(volatile unsigned short * w){ int t = *w; *w = (t>>8) | ((t & 0xff)<<8);}/* Init control register bits on interface card. * For Archive, interrupts must be enabled explicitly. * Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R * cards keep it active all the time. */static void ifc_init(void){#if TAPE_QIC02_IFC == WANGTEK ctlbits = WT_CTL_ONLINE; /* online */ outb_p(ctlbits, QIC_CTL_PORT);#elif TAPE_QIC02_IFC == ARCHIVE ctlbits = 0; /* no interrupts yet */ outb_p(ctlbits, QIC_CTL_PORT); outb_p(0, AR_RESET_DMA_PORT); /* dummy write to reset DMA */#else# error No valid interface card specified#endif} /* ifc_init */static void report_exception(unsigned n){ if (n >= NR_OF_EXC) { tpqputs("Oops -- report_exception"); n = 0; } printk(TPQIC_NAME ": sense: %s\n", exception_list[n].msg);} /* report_exception *//* Try to map the drive-exception bits `s' to a predefined "exception number", * by comparing the significant exception bits for each entry in the * exception table (`exception_list[]'). * It is assumed that s!=0.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -