📄 ut.c
字号:
#ifndef lintstatic char *sccsid = "@(#)ut.c 4.1 ULTRIX 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1984, 1986, 1989 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * ut.c 6.1 07/29/83 * * Modification history * * TU45 tape driver * System Industries Model 9700 Tape Drive, * emulates a TU45 on the UNIBUS. * * 9-Feb-86 - ricky palmer * * Derived from 4.2BSD labeled: ut.c 6.1 83/07/29. * Added new ioctl functionality as well as new code to handle * EOT correctly. Driver now supports new minor number convention * to allow for more than 4 tape devices. V2.0 * * 18-Mar-86 - jaw * * br/cvec changed to NOT use registers. * * 19-Mar-86 - ricky palmer * * Added new DEVIOCGET ioctl request code. V2.0 * * 13-Jun-86 - jaw * * Fix to uba reset and drivers. * * 11-Jul-86 - ricky palmer * * Added adpt and nexus fields to DEVIOCGET code. * * 26-Aug-86 - rsp (Ricky Palmer) * * Cleaned up devioctl code to (1) zero out devget structure * upon entry and (2) use strlen instead of fixed storage * for bcopy's. * * 14-Aug-87 - rjl * * Fixed two mprintf's that had a extra argument which caused * the system to panic when a tape error was encountered. * * 05-Jun-89 - Tim Burke * Added a new MTIOCTOP called MTFLUSH. This is used on caching drives * to force a flush of the controller's write back cache. Since this * is not a caching drive the MTFLUSH always returns ENXIO. */#include "tj.h"#if NUT > 0 || defined(BINARY)#include "../data/ut_data.c"u_short utstd[] = { UTSTD, 0 };int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer();struct uba_driver utdriver = { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 };utprobe(reg) caddr_t reg;{#ifdef lint utintr(0);#endif /* * The SI documentation says you must set the RDY bit * (even though it's read-only) to force an interrupt. */ ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; DELAY(10000); return (sizeof (struct utdevice));}utslave(ui, reg) struct uba_device *ui; caddr_t reg;{ /* * A real TU45 would support the slave present bit * int the drive type register, but this thing doesn't, * so there's no way to determine if a slave is present or not. */ return(1);}utattach(ui) struct uba_device *ui;{ register struct tj_softc *sc = &tj_softc[ui->ui_unit]; tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; bcopy(DEV_UNKNOWN,sc->sc_device,strlen(DEV_UNKNOWN));}/* * Open the device with exclusive access. */utopen(dev, flag) register dev_t dev; register int flag;{ register struct uba_device *ui; register struct tj_softc *sc; register struct utdevice *utaddr; register int sel = SEL(dev); int unit = UNIT(dev); int s; if (unit >= nNTJ || (sc = &tj_softc[unit])->sc_openf || (ui = tjdinfo[unit]) == 0 || ui->ui_alive == 0) { return (ENXIO); } utaddr = (struct utdevice *)ui->ui_addr; if ((utaddr->utds & UTDS_EOT) && (dis_eot_tj[unit] != DISEOT)) { sc->sc_flags &= DEV_EOM; } else { sc->sc_flags = 0; } sc->sc_category_flags = 0; sc->sc_dens = (((sel == MTHR) || (sel == MTHN)) ? UTTC_GCR : ((sel == MTMR) || (sel == MTMN)) ? UTTC_PE : UTTC_NRZI) | UTTC_PDP11FMT | (ui->ui_slave&07); if((sel == MTHR) || (sel == MTHN)) { sc->sc_category_flags |= DEV_6250BPI; } if((sel == MTMR) || (sel == MTMN)) { sc->sc_category_flags |= DEV_1600BPI; } if((sel == MTLR) || (sel == MTLN)) { sc->sc_category_flags |= DEV_800BPI; }get: utcommand(dev, UT_SENSE, 1); if (sc->sc_dsreg & UTDS_PIP) { sleep((caddr_t) & lbolt, PZERO+1); goto get; } if ((sc->sc_dsreg & UTDS_MOL) == 0) { sc->sc_flags |= DEV_OFFLINE; if(!(flag & FNDELAY)) { DEV_UGH(sc->sc_device,unit,"offline"); return(EIO); } } if ((flag & FWRITE) && (sc->sc_dsreg & UTDS_WRL)) { sc->sc_flags |= DEV_WRTLCK; if(!(flag & FNDELAY)) { DEV_UGH(sc->sc_device,unit,"write locked"); return(EIO); } } sc->sc_openf = 1; sc->sc_blkno = (daddr_t)0; sc->sc_nxrec = INF; /* * For 6250 bpi take exclusive use of the UNIBUS. */ ui->ui_driver->ud_xclu = (sc->sc_dens & (UTTC_PE|UTTC_GCR)) == UTTC_GCR; s = spl6(); if (sc->sc_tact == 0) { sc->sc_timo = INF; sc->sc_tact = 1; timeout(uttimer, (caddr_t)dev, 5*hz); } splx(s); return (0);}utclose(dev, flag) register dev_t dev; register int flag;{ register struct tj_softc *sc = &tj_softc[UNIT(dev)]; register int unit = UNIT(dev); register int sel = SEL(dev); sc->sc_flags &= ~DEV_EOM; if (flag == FWRITE || (flag & FWRITE) && (sc->sc_flags & DEV_WRITTEN)) { utcommand(dev, UT_WEOF, 1); sc->sc_flags &= ~DEV_EOM; utcommand(dev, UT_WEOF, 1); sc->sc_flags &= ~DEV_EOM; utcommand(dev, UT_SREV, 1); sc->sc_flags &= ~DEV_EOM; } if ((sel == MTLR) || (sel == MTMR) || (sel == MTHR)) { utcommand(dev, UT_REW, 0); } sc->sc_openf = 0; if ((sc->sc_dsreg & UTDS_EOT) && (dis_eot_tj[unit] != DISEOT)) { sc->sc_flags |= DEV_EOM; }}utcommand(dev, com, count) register dev_t dev; register int com; register int count;{ register struct buf *bp = &cutbuf[UTUNIT(dev)]; register int s = spl5(); while (bp->b_flags&B_BUSY) { if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) break; bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO); } bp->b_flags = B_BUSY|B_READ; splx(s); bp->b_dev = dev; bp->b_command = com; bp->b_repcnt = count; bp->b_blkno = 0; utstrategy(bp); if (count == 0) return; iowait(bp); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); bp->b_flags &= B_ERROR;}/* * Queue a tape operation. */utstrategy(bp) register struct buf *bp;{ register struct uba_ctlr *um; register struct tj_softc *sc = &tj_softc[UNIT(bp->b_dev)]; register struct buf *dp; register int s; register int unit = UNIT(bp->b_dev); if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) || (dis_eot_tj[unit] & DISEOT))) { bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; iodone(bp); return; } sc->sc_category_flags &= ~DEV_TPMARK; /* * Put transfer at end of unit queue */ dp = &tjutab[unit]; bp->av_forw = NULL; s = spl5(); if (dp->b_actf == NULL) { dp->b_actf = bp; /* * Transport not active, so... * put at end of controller queue */ dp->b_forw = NULL; um = tjdinfo[unit]->ui_mi; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; } else dp->b_actl->av_forw = bp; dp->b_actl = bp; /* * If the controller is not busy, set it going. */ if (um->um_tab.b_state == 0) utstart(um); splx(s);}utstart(um) register struct uba_ctlr *um;{ register struct utdevice *addr = (struct utdevice *)um->um_addr; register struct buf *bp, *dp; register struct tj_softc *sc; register struct uba_device *ui; int utunit, unit; daddr_t blkno;loop: /* * Scan controller queue looking for units with * transaction queues to dispatch */ if ((dp = um->um_tab.b_actf) == NULL) return; if ((bp = dp->b_actf) == NULL) { um->um_tab.b_actf = dp->b_forw; goto loop; } utunit = UTUNIT(bp->b_dev); unit = UNIT(bp->b_dev); ui = tjdinfo[unit]; sc = &tj_softc[unit]; /* note slave select, density, and format were merged on open */ addr->uttc = sc->sc_dens; sc->sc_dsreg = addr->utds; sc->sc_erreg = addr->uter; sc->sc_resid = MASKREG(addr->utfc); if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) || (dis_eot_tj[unit] & DISEOT))) { bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; goto next; } if ((sc->sc_category_flags & DEV_TPMARK) && (bp->b_flags & B_READ)) { bp->b_resid = 0; bp->b_error = EIO; bp->b_flags |= B_ERROR; goto next; } /* * Default is that last command was NOT a write command; * if we do a write command we will notice this in utintr(). */ sc->sc_flags &= ~DEV_WRITTEN; if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { /* * Have had a hard error on a non-raw tape * or the tape unit is now unavailable * (e.g. taken off line). */ bp->b_flags |= B_ERROR; goto next; } if (bp == &cutbuf[utunit]) { /* * Execute a control operation with the specified * count. */ if (bp->b_command == UT_SENSE) goto next; /* * Set next state; handle timeouts */ if (bp->b_command == UT_REW) { um->um_tab.b_state = SREW; sc->sc_timo = 5*60; } else { um->um_tab.b_state = SCOM; sc->sc_timo = imin(imax(10*(int)- bp->b_repcnt,60),5*60); } if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) addr->utfc = -bp->b_repcnt; goto dobpcmd; } if (sc->sc_blkno != bdbtofsb(bp->b_blkno) && !um->um_tab.b_errcnt) sc->sc_blkno = bdbtofsb(bp->b_blkno); sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; /* * If the tape is correctly positioned, set up all the * registers but the csr, and give control over to the * UNIBUS adaptor routines, to wait for resources to * start I/O. */ if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { addr->utwc = -(((bp->b_bcount)+1)>>1); addr->utfc = -bp->b_bcount; if ((bp->b_flags&B_READ) == 0) { /* * On write error retries erase the * inter-record gap before rewriting. */ if (um->um_tab.b_errcnt) { if (um->um_tab.b_state != SERASED) { um->um_tab.b_state = SERASE; sc->sc_timo = 60; addr->utcs1 = UT_ERASE|UT_IE| UT_GO; return; } } um->um_cmd = UT_WCOM; } else um->um_cmd = UT_RCOM; sc->sc_timo = 60; um->um_tab.b_state = SIO; (void) ubago(ui); return; } /* * Tape positioned incorrectly; seek forwards or * backwards to the correct spot. This happens for * raw tapes only on error retries. */ um->um_tab.b_state = SSEEK; if (blkno < bdbtofsb(bp->b_blkno)) { addr->utfc = blkno - bdbtofsb(bp->b_blkno); bp->b_command = UT_SFORW; } else { addr->utfc = bdbtofsb(bp->b_blkno) - blkno; bp->b_command = UT_SREV; } sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60);dobpcmd: /* * Perform the command setup in bp. */ addr->utcs1 = bp->b_command|UT_IE|UT_GO; return;next: /* * Advance to the next command in the slave queue, * posting notice and releasing resources as needed. */ if (um->um_ubinfo) ubadone(um); um->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; iodone(bp); goto loop;}/* * Start operation on controller -- * UNIBUS resources have been allocated. */utdgo(um) register struct uba_ctlr *um;{ register struct utdevice *addr = (struct utdevice *)um->um_addr; addr->utba = (u_short) um->um_ubinfo; addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO;}/* * UT interrupt handler */utintr(ut11) int ut11;{ register struct buf *bp; register struct uba_ctlr *um = utminfo[ut11]; register struct utdevice *addr; register struct tj_softc *sc; register int state; register struct buf *dp; int utunit, unit; u_short cs2, cs1; if ((dp = um->um_tab.b_actf) == NULL) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -