⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cy.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Computer Consoles Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * *	@(#)cy.c	7.8 (Berkeley) 5/8/91 */#include "yc.h"#if NCY > 0/* * Cipher Tapemaster driver. */#define CYDEBUG#ifdef	CYDEBUGint	cydebug = 0;#define	dlog(params)	if (cydebug) log params#else#define dlog(params)	/* */#endif#include "sys/param.h"#include "sys/systm.h"#include "sys/vm.h"#include "sys/buf.h"#include "sys/file.h"#include "sys/signal.h"#include "sys/ioctl.h"#include "sys/mtio.h"#include "sys/errno.h"#include "sys/cmap.h"#include "sys/time.h"#include "sys/kernel.h"#include "sys/syslog.h"#include "sys/tprintf.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "../include/pte.h"#include "../vba/vbavar.h"#define	CYERROR#include "../vba/cyreg.h"/* * There is a ccybuf per tape controller. * It is used as the token to pass to the internal routines * to execute tape ioctls, and also acts as a lock on the slaves * on the controller, since there is only one per controller. * In particular, when the tape is rewinding on close we release * the user process but any further attempts to use the tape drive * before the rewind completes will hang waiting for ccybuf. */struct	buf ccybuf[NCY];int	cyprobe(), cyslave(), cyattach();struct	buf ycutab[NYC];short	yctocy[NYC];struct	vba_ctlr *cyminfo[NCY];struct	vba_device *ycdinfo[NYC];long	cystd[] = { 0 };struct	vba_driver cydriver =   { cyprobe, cyslave, cyattach, 0, cystd, "yc", ycdinfo, "cy", cyminfo };/* bits in minor device */#define	YCUNIT(dev)	(minor(dev)&03)#define	CYUNIT(dev)	(yctocy[YCUNIT(dev)])#define	T_NOREWIND	0x04#define	T_1600BPI	0x00		/* pseudo */#define	T_3200BPI	0x08		/* unused */#define	INF	1000000L		/* close to infinity *//* * Software state and shared command areas per controller. * * The i/o intermediate buffer must be allocated in startup() * so its address will fit in 20-bits (YECH!!!!!!!!!!!!!!). */struct cy_softc {	int	cy_bs;		/* controller's buffer size */	struct	cyscp *cy_scp;	/* system configuration block address */	struct	cyccb cy_ccb;	/* channel control block */	struct	cyscb cy_scb;	/* system configuration block */	struct	cytpb cy_tpb;	/* tape parameter block */	struct	cytpb cy_nop;	/* nop parameter block for cyintr */	struct	vb_buf cy_rbuf;	/* vba resources */} cy_softc[NCY];/* * Software state per tape transport. */struct	yc_softc {	char	yc_openf;	/* lock against multiple opens */	char	yc_lastiow;	/* last operation was a write */	short	yc_tact;	/* timeout is active */	long	yc_timo;	/* time until timeout expires */	u_short	yc_control;	/* copy of last tpcb.tpcontrol */	u_short	yc_status;	/* copy of last tpcb.tpstatus */	u_short	yc_resid;	/* copy of last bc */	u_short	yc_dens;	/* prototype control word with density info */	tpr_t	yc_tpr;		/* handle for tprintf */	daddr_t	yc_blkno;	/* block number, for block device tape */	daddr_t	yc_nxrec;	/* position of end of tape, if known */	int	yc_blksize;	/* current tape blocksize estimate */	int	yc_blks;	/* number of I/O operations since open */	int	yc_softerrs;	/* number of soft I/O errors since open */} yc_softc[NYC];/* * States for vm->um_tab.b_active, the per controller state flag. * This is used to sequence control in the driver. */#define	SSEEK	1		/* seeking */#define	SIO	2		/* doing seq i/o */#define	SCOM	3		/* sending control command */#define	SREW	4		/* sending a rewind */#define	SERASE	5		/* erase inter-record gap */#define	SERASED	6		/* erased inter-record gap *//* there's no way to figure these out dynamically? -- yech */struct	cyscp *cyscp[] =    { (struct cyscp *)0xc0000c06, (struct cyscp *)0xc0000c16 };#define	NCYSCP	(sizeof (cyscp) / sizeof (cyscp[0]))cyprobe(reg, vm)	caddr_t reg;	struct vba_ctlr *vm;{	register br, cvec;			/* must be r12, r11 */	register struct cy_softc *cy;	int ctlr = vm->um_ctlr;#ifdef lint	br = 0; cvec = br; br = cvec;	cyintr(0);#endif	if (badcyaddr(reg+1))		return (0);	if (ctlr > NCYSCP || cyscp[ctlr] == 0)		/* XXX */		return (0);	cy = &cy_softc[ctlr];	cy->cy_scp = cyscp[ctlr];			/* XXX */	/*	 * Tapemaster controller must have interrupt handler	 * disable interrupt, so we'll just kludge things	 * (stupid multibus non-vectored interrupt crud).	 */	if (cyinit(ctlr, reg)) {		uncache(&cy->cy_tpb.tpcount);		cy->cy_bs = htoms(cy->cy_tpb.tpcount);		/*		 * Setup nop parameter block for clearing interrupts.		 */		cy->cy_nop.tpcmd = CY_NOP;		cy->cy_nop.tpcontrol = 0;		/*		 * Allocate page tables.		 */		if (cybuf == 0) {			printf("no cy buffer!!!\n");			return (0);		}		cy->cy_rbuf.vb_rawbuf = cybuf + ctlr * CYMAXIO;		if (vbainit(&cy->cy_rbuf, CYMAXIO, VB_20BIT) == 0) {			printf("cy%d: vbainit failed\n", ctlr);			return (0);		}		br = 0x13, cvec = 0x80;			/* XXX */		return (sizeof (struct cyccb));	} else		return (0);}/* * Check to see if a drive is attached to a controller. * Since we can only tell that a drive is there if a tape is loaded and * the drive is placed online, we always indicate the slave is present. */cyslave(vi, addr)	struct vba_device *vi;	caddr_t addr;{#ifdef lint	vi = vi; addr = addr;#endif	return (1);}cyattach(vi)	struct vba_device *vi;{	register struct cy_softc *cy;	int ctlr = vi->ui_mi->um_ctlr;	yctocy[vi->ui_unit] = ctlr;	cy = &cy_softc[ctlr];	if (vi->ui_slave == 0 && cy->cy_bs)		printf("; %dkb buffer", cy->cy_bs/1024);}/* * Initialize the controller after a controller reset or * during autoconfigure.  All of the system control blocks * are initialized and the controller is asked to configure * itself for later use. */cyinit(ctlr, addr)	int ctlr;	register caddr_t addr;{	register struct cy_softc *cy = &cy_softc[ctlr];	register int *pte;	/*	 * Initialize the system configuration pointer.	 */	/* make kernel writable */	pte = (int *)&Sysmap[btop((int)cy->cy_scp &~ KERNBASE)]; 	*pte &= ~PG_PROT; *pte |= PG_KW;	mtpr(TBIS, cy->cy_scp);	/* load the correct values in the scp */	cy->cy_scp->csp_buswidth = CSP_16BITS;	cyldmba(cy->cy_scp->csp_scb, (caddr_t)&cy->cy_scb);	/* put it back to read-only */	*pte &= ~PG_PROT; *pte |= PG_KR;	mtpr(TBIS, cy->cy_scp);	/*	 * Init system configuration block.	 */	cy->cy_scb.csb_fixed = CSB_FIXED;	/* set pointer to the channel control block */	cyldmba(cy->cy_scb.csb_ccb, (caddr_t)&cy->cy_ccb);	/*	 * Initialize the chanel control block.	 */	cy->cy_ccb.cbcw = CBCW_CLRINT;	cy->cy_ccb.cbgate = GATE_OPEN;	/* set pointer to the tape parameter block */	cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);	/*	 * Issue a nop cmd and get the internal buffer size for buffered i/o.	 */	cy->cy_tpb.tpcmd = CY_NOP;	cy->cy_tpb.tpcontrol = CYCW_16BITS;	cy->cy_ccb.cbgate = GATE_CLOSED;		CY_GO(addr);	if (cywait(&cy->cy_ccb) || (cy->cy_tpb.tpstatus&CYS_ERR)) {		uncache(&cy->cy_tpb.tpstatus);		printf("cy%d: timeout or err during init, status=%b\n", ctlr,		    cy->cy_tpb.tpstatus, CYS_BITS);		return (0);	}	cy->cy_tpb.tpcmd = CY_CONFIG;	cy->cy_tpb.tpcontrol = CYCW_16BITS;	cy->cy_ccb.cbgate = GATE_CLOSED;		CY_GO(addr);	if (cywait(&cy->cy_ccb) || (cy->cy_tpb.tpstatus&CYS_ERR)) {		uncache(&cy->cy_tpb.tpstatus);		printf("cy%d: configuration failure, status=%b\n", ctlr,		    cy->cy_tpb.tpstatus, CYS_BITS);		return (0);	}	return (1);}int	cytimer();/* * Open the device.  Tapes are unique open * devices, so we refuse if it is already open. * We also check that a tape is available, and * don't block waiting here; if you want to wait * for a tape you should timeout in user code. */cyopen(dev, flag)	dev_t dev;	register int flag;{	register int ycunit;	register struct vba_device *vi;	register struct yc_softc *yc;	ycunit = YCUNIT(dev);	if (ycunit >= NYC || (vi = ycdinfo[ycunit]) == 0 || vi->ui_alive == 0)		return (ENXIO);	if ((yc = &yc_softc[ycunit])->yc_openf)		return (EBUSY);	yc->yc_openf = 1;#define	PACKUNIT(vi) \    (((vi->ui_slave&1)<<11)|((vi->ui_slave&2)<<9)|((vi->ui_slave&4)>>2))	/* no way to select density */	yc->yc_dens = PACKUNIT(vi)|CYCW_IE|CYCW_16BITS;	if (yc->yc_tact == 0) {		yc->yc_timo = INF;		yc->yc_tact = 1;		timeout(cytimer, (caddr_t)dev, 5*hz);	}	cycommand(dev, CY_SENSE, 1);	if ((yc->yc_status&CYS_OL) == 0) {	/* not on-line */		uprintf("cy%d: not online\n", ycunit);		yc->yc_openf = 0;		return (EIO);	}	if ((flag&FWRITE) && (yc->yc_status&CYS_WP)) {		uprintf("cy%d: no write ring\n", ycunit);		yc->yc_openf = 0;		return (EIO);	}	yc->yc_blkno = (daddr_t)0;	yc->yc_nxrec = INF;	yc->yc_lastiow = 0;	yc->yc_blksize = CYMAXIO;		/* guess > 0 */	yc->yc_blks = 0;	yc->yc_softerrs = 0;	yc->yc_tpr = tprintf_open();	return (0);}/* * Close tape device. * * If tape was open for writing or last operation was a write, * then write two EOF's and backspace over the last one. * Unless this is a non-rewinding special file, rewind the tape. * Make the tape available to others. */cyclose(dev, flag)	dev_t dev;	int flag;{	struct yc_softc *yc = &yc_softc[YCUNIT(dev)];	if (flag == FWRITE || (flag&FWRITE) && yc->yc_lastiow) {		cycommand(dev, CY_WEOF, 1);	/* can't use count with WEOF */		cycommand(dev, CY_WEOF, 1);		cycommand(dev, CY_SREV, 1);	}	if ((minor(dev)&T_NOREWIND) == 0)		/*		 * 0 count means don't hang waiting for rewind complete		 * rather ccybuf stays busy until the operation completes		 * preventing further opens from completing by preventing		 * a CY_SENSE from completing.		 */		cycommand(dev, CY_REW, 0);	if (yc->yc_blks > 10 && yc->yc_softerrs > yc->yc_blks / 10)		log(LOG_INFO, "yc%d: %d soft errors in %d blocks\n",		    YCUNIT(dev), yc->yc_softerrs, yc->yc_blks);	dlog((LOG_INFO, "%d soft errors in %d blocks\n",	    yc->yc_softerrs, yc->yc_blks));	tprintf_close(yc->yc_tpr);	yc->yc_openf = 0;	return (0);}/* * Execute a command on the tape drive a specified number of times. */cycommand(dev, com, count)	dev_t dev;	int com, count;{	register struct buf *bp;	int s;		bp = &ccybuf[CYUNIT(dev)];	s = spl3();	dlog((LOG_INFO, "cycommand(%o, %x, %d), b_flags %x\n",	    dev, com, count, bp->b_flags));	while (bp->b_flags&B_BUSY) {		/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -