📄 cy.c
字号:
/* * 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 + -