?? tpqic02.c
字號(hào):
/* $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 */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -