X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/0a51498ead57beb885d7a5f15e32f51563792876..809050756a30fe4d50aa9388e51f189e1cdafee0:/usr/src/sys/vax/uba/tm.c diff --git a/usr/src/sys/vax/uba/tm.c b/usr/src/sys/vax/uba/tm.c index 8baf20f0f0..cd5e51af43 100644 --- a/usr/src/sys/vax/uba/tm.c +++ b/usr/src/sys/vax/uba/tm.c @@ -1,11 +1,17 @@ -/* tm.c 4.2 %G% */ +/* tm.c 4.22 %G% */ -#include "../conf/tm.h" +#include "te.h" #if NTM > 0 +int tmgapsdcnt; /* DEBUG */ /* - * TM tape driver + * TM11/TE10 tape driver + * + * Todo: + * Test driver with more than one slave + * Test reset code + * Do rewinds without hanging in driver */ - +#define DELAY(N) { register int d = N; while (--d > 0); } #include "../h/param.h" #include "../h/buf.h" #include "../h/dir.h" @@ -14,168 +20,191 @@ #include "../h/file.h" #include "../h/map.h" #include "../h/pte.h" +#include "../h/vm.h" #include "../h/uba.h" #include "../h/mtio.h" #include "../h/ioctl.h" -#include "../h/vm.h" - -struct device { - u_short tmer; - u_short tmcs; - short tmbc; - u_short tmba; - short tmdb; - short tmrd; -}; +#include "../h/cmap.h" +#include "../h/cpu.h" -#define b_repcnt b_bcount -#define b_command b_resid +#include "../h/tmreg.h" -struct buf tmtab; -struct buf ctmbuf; -struct buf rtmbuf; +struct buf ctmbuf[NTE]; +struct buf rtmbuf[NTE]; -int tm_ubinfo; +int tmprobe(), tmslave(), tmattach(), tmdgo(), tmintr(); +struct uba_minfo *tmminfo[NTM]; +struct uba_dinfo *tmdinfo[NTE]; +struct buf tmutab[NTE]; +#ifdef notyet +struct uba_dinfo *tmip[NTM][4]; +#endif +u_short tmstd[] = { 0772520, 0 }; +struct uba_driver tmdriver = + { tmprobe, tmslave, tmattach, tmdgo, tmstd, "te", tmdinfo, "tm", tmminfo, 0 }; /* bits in minor device */ +#define TMUNIT(dev) (minor(dev)&03) #define T_NOREWIND 04 #define T_1600BPI 08 #define INF (daddr_t)1000000L /* - * Really only handle one tape drive... if you have more than one, - * you can make all these arrays and change the obvious things, but - * it is not clear what happens when some drives are transferring while - * others rewind, so we don't pretend that this driver handles multiple - * tape drives. + * Software state per tape transport. */ -char t_openf; -daddr_t t_blkno; -char t_flags; -daddr_t t_nxrec; -u_short t_erreg; -u_short t_dsreg; -short t_resid; - -/* bits in tmcs */ -#define GO 01 -#define OFFL 0 -#define RCOM 02 -#define WCOM 04 -#define WEOF 06 -#define SFORW 010 -#define SREV 012 -#define WIRG 014 -#define REW 016 -#define IENABLE 0100 -#define CUR 0200 -#define NOP IENABLE -#define DCLR 010000 -#define D800 060000 -#define ERROR 0100000 - -/* bits in tmer */ -#define TUR 1 -#define RWS 02 -#define WRL 04 -#define SDWN 010 -#define BOT 040 -#define SELR 0100 -#define NXM 0200 -#define TMBTE 0400 -#define RLE 01000 -#define EOT 02000 -#define BGL 04000 -#define PAE 010000 -#define CRE 020000 -#define EOF 040000 -#define ILC 0100000 - -#define HARD (ILC|EOT) -#define SOFT (CRE|PAE|BGL|RLE|TMBTE|NXM) +struct tm_softc { + char sc_openf; /* lock against multiple opens */ + char sc_lastiow; /* last op was a write */ + daddr_t sc_blkno; /* block number, for block device tape */ + daddr_t sc_nxrec; /* desired block position */ + u_short sc_erreg; /* copy of last erreg */ + u_short sc_dsreg; /* copy of last dsreg */ + short sc_resid; /* copy of last bc */ +#ifdef notdef + short sc_lastcmd; /* last command to handle direction changes */ +#endif +} tm_softc[NTM]; +/* + * States for um->um_tab.b_active, the + * per controller state flag. + */ #define SSEEK 1 /* seeking */ #define SIO 2 /* doing seq i/o */ #define SCOM 3 /* sending control command */ +#define SREW 4 /* sending a drive rewind */ -#define LASTIOW 1 /* last op was a write */ -#define WAITREW 2 /* someone is waiting for a rewind */ +/* WE CURRENTLY HANDLE REWINDS PRIMITIVELY, BUSYING OUT THE CONTROLLER */ +/* DURING THE REWIND... IF WE EVER GET TWO TRANSPORTS, WE CAN DEBUG MORE */ +/* SOPHISTICATED LOGIC... THIS SIMPLE CODE AT LEAST MAY WORK. */ + +/* + * Determine if there is a controller for + * a tm at address reg. Our goal is to make the + * device interrupt. + */ +tmprobe(reg) + caddr_t reg; +{ + register int br, cvec; + +#ifdef lint + br = 0; br = cvec; cvec = br; +#endif + ((struct device *)reg)->tmcs = TM_IE; + /* + * If this is a tm11, it ought to have interrupted + * by now, if it isn't (ie: it is a ts04) then we just + * hope that it didn't interrupt, so autoconf will ignore it. + * Just in case, we will reference one + * of the more distant registers, and hope for a machine + * check, or similar disaster if this is a ts. + * + * Note: on an 11/780, badaddr will just generate + * a uba error for a ts; but our caller will notice that + * so we won't check for it. + */ + if (badaddr(&((struct device *)reg)->tmrd, 2)) + return (0); + return (1); +} + +/* + * Due to a design flaw, we cannot ascertain if the tape + * exists or not unless it is on line - ie: unless a tape is + * mounted. This is too servere a restriction to bear, + * so all units are assumed to exist. + */ +/*ARGSUSED*/ +tmslave(ui, reg) + struct uba_dinfo *ui; + caddr_t reg; +{ + + return (1); +} + +/* + * Record attachment of the unit to the controller port. + */ +/*ARGSUSED*/ +tmattach(ui) + struct uba_dinfo *ui; +{ + +#ifdef notyet + tmip[ui->ui_ctlr][ui->ui_slave] = ui; +#endif +} +/* + * 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. + */ tmopen(dev, flag) dev_t dev; int flag; { - register ds, unit; + register int unit; + register struct uba_dinfo *ui; + register struct tm_softc *sc; - tmtab.b_flags |= B_TAPE; - unit = minor(dev)&03; - if (unit >= NTM || t_openf) { - u.u_error = ENXIO; /* out of range or open */ - return; - } - tcommand(dev, NOP, 1); - if ((t_erreg&SELR) == 0) { - u.u_error = EIO; /* offline */ + unit = TMUNIT(dev); + if (unit>=NTE || (sc = &tm_softc[unit])->sc_openf || + (ui = tmdinfo[unit]) == 0 || ui->ui_alive == 0) { + u.u_error = ENXIO; return; } - t_openf = 1; - if (t_erreg&RWS) - tmwaitrws(dev); /* wait for rewind complete */ - while (t_erreg&SDWN) - tcommand(dev, NOP, 1); /* await settle down */ - if ((t_erreg&TUR)==0 || - ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) { - TMADDR->tmcs = DCLR|GO; - u.u_error = EIO; /* offline or write protect */ - } - if (u.u_error != 0) { - t_openf = 0; + tmcommand(dev, TM_SENSE, 1); + if ((sc->sc_erreg&(TM_SELR|TM_TUR)) != (TM_SELR|TM_TUR) || + (flag&(FREAD|FWRITE)) == FWRITE && sc->sc_erreg&TM_WRL) { + u.u_error = EIO; return; } - t_blkno = (daddr_t)0; - t_nxrec = INF; - t_flags = 0; - t_openf = 1; -} - -tmwaitrws(dev) - register dev; -{ - - spl5(); - for (;;) { - if ((TMADDR->tmer&RWS) == 0) { - spl0(); /* rewind complete */ - return; - } - t_flags |= WAITREW; - sleep((caddr_t)&t_flags, PRIBIO); - } + sc->sc_openf = 1; + sc->sc_blkno = (daddr_t)0; + sc->sc_nxrec = INF; + sc->sc_lastiow = 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. + */ tmclose(dev, flag) register dev_t dev; register flag; { + register struct tm_softc *sc = &tm_softc[TMUNIT(dev)]; - if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { - tcommand(dev, WEOF, 1); - tcommand(dev, WEOF, 1); - tcommand(dev, SREV, 1); + if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { + tmcommand(dev, TM_WEOF, 1); + tmcommand(dev, TM_WEOF, 1); + tmcommand(dev, TM_SREV, 1); } if ((minor(dev)&T_NOREWIND) == 0) - tcommand(dev, REW, 1); - t_openf = 0; + tmcommand(dev, TM_REW, 1); + sc->sc_openf = 0; } -tcommand(dev, com, count) +/* + * Execute a command on the tape drive + * a specified number of times. + */ +tmcommand(dev, com, count) dev_t dev; int com, count; { register struct buf *bp; - bp = &ctmbuf; + bp = &ctmbuf[TMUNIT(dev)]; (void) spl5(); while (bp->b_flags&B_BUSY) { bp->b_flags |= B_WANTED; @@ -194,245 +223,465 @@ tcommand(dev, com, count) bp->b_flags &= B_ERROR; } +/* + * Decipher a tape operation and do what is needed + * to see that it happens. + */ tmstrategy(bp) register struct buf *bp; { - register daddr_t *p; - - tmwaitrws(bp->b_dev); - if (bp != &ctmbuf) { - p = &t_nxrec; - if (dbtofsb(bp->b_blkno) > *p) { - bp->b_flags |= B_ERROR; - bp->b_error = ENXIO; /* past EOF */ - iodone(bp); - return; - } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { - bp->b_resid = bp->b_bcount; - clrbuf(bp); /* at EOF */ - iodone(bp); - return; - } else if ((bp->b_flags&B_READ) == 0) - *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ - } + int unit = TMUNIT(bp->b_dev); + register struct uba_minfo *um; + register struct buf *dp; + register struct tm_softc *sc = &tm_softc[unit]; + + /* + * Put transfer at end of unit queue + */ + dp = &tmutab[unit]; bp->av_forw = NULL; (void) spl5(); - if (tmtab.b_actf == NULL) - tmtab.b_actf = bp; - else - tmtab.b_actl->av_forw = bp; - tmtab.b_actl = bp; - if (tmtab.b_active == 0) - tmstart(); + if (dp->b_actf == NULL) { + dp->b_actf = bp; + /* + * Transport not already active... + * put at end of controller queue. + */ + dp->b_forw = NULL; + um = tmdinfo[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, get + * it going. + */ + if (um->um_tab.b_active == 0) + tmstart(um); (void) spl0(); } -tmstart() +/* + * Start activity on a tm controller. + */ +tmstart(um) + register struct uba_minfo *um; { - register struct buf *bp; - register cmd; - register daddr_t blkno; - + register struct buf *bp, *dp; + register struct device *addr = (struct device *)um->um_addr; + register struct tm_softc *sc; + register struct uba_dinfo *ui; + int unit, cmd; + daddr_t blkno; + + /* + * Look for an idle transport on the controller. + */ loop: - if ((bp = tmtab.b_actf) == 0) + if ((dp = um->um_tab.b_actf) == NULL) return; - t_dsreg = TMADDR->tmcs; - t_erreg = TMADDR->tmer; - t_resid = TMADDR->tmbc; - t_flags &= ~LASTIOW; - if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) { - /* t_openf = -1; ??? */ - bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ + if ((bp = dp->b_actf) == NULL) { + um->um_tab.b_actf = dp->b_forw; + goto loop; + } + unit = TMUNIT(bp->b_dev); + ui = tmdinfo[unit]; + /* + * Record pre-transfer status (e.g. for TM_SENSE) + */ + sc = &tm_softc[unit]; + addr = (struct device *)um->um_addr; + addr->tmcs = (ui->ui_slave << 8); + sc->sc_dsreg = addr->tmcs; + sc->sc_erreg = addr->tmer; + sc->sc_resid = addr->tmbc; + /* + * Default is that last command was NOT a write command; + * if we do a write command we will notice this in tmintr(). + */ + sc->sc_lastiow = 1; + if (sc->sc_openf < 0 || (addr->tmcs&TM_CUR) == 0) { + /* + * Have had a hard error on this (non-raw) tape, + * or the tape unit is now unavailable (e.g. taken off + * line). + */ + bp->b_flags |= B_ERROR; goto next; } - cmd = IENABLE | GO; - if ((minor(bp->b_dev) & T_1600BPI) == 0) - cmd |= D800; - if (bp == &ctmbuf) { - if (bp->b_command == NOP) - goto next; /* just get status */ - else { - cmd |= bp->b_command; - tmtab.b_active = SCOM; - if (bp->b_command == SFORW || bp->b_command == SREV) - TMADDR->tmbc = bp->b_repcnt; - TMADDR->tmcs = cmd; - return; + /* + * If operation is not a control operation, + * check for boundary conditions. + */ + if (bp != &ctmbuf[unit]) { + if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { + bp->b_flags |= B_ERROR; + bp->b_error = ENXIO; /* past EOF */ + goto next; + } + if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && + bp->b_flags&B_READ) { + bp->b_resid = bp->b_bcount; + clrbuf(bp); /* at EOF */ + goto next; } + if ((bp->b_flags&B_READ) == 0) + /* write sets EOF */ + sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1; } - if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { - TMADDR->tmbc = -bp->b_bcount; - if (tm_ubinfo == 0) - tm_ubinfo = ubasetup(bp,1); + /* + * Set up the command, and then if this is a mt ioctl, + * do the operation using, for TM_SFORW and TM_SREV, the specified + * operation count. + */ + cmd = TM_IE | TM_GO | (ui->ui_slave << 8); + if ((minor(bp->b_dev) & T_1600BPI) == 0) + cmd |= TM_D800; + if (bp == &ctmbuf[unit]) { + if (bp->b_command == TM_SENSE) + goto next; + um->um_tab.b_active = + bp->b_command == TM_REW ? SREW : SCOM; + if (bp->b_command == TM_SFORW || bp->b_command == TM_SREV) + addr->tmbc = bp->b_repcnt; + goto dobpcmd; + } + /* + * If the data transfer command is in the correct place, + * set up all the registers except the csr, and give + * control over to the UNIBUS adapter routines, to + * wait for resources to start the i/o. + */ + if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { + addr->tmbc = -bp->b_bcount; if ((bp->b_flags&B_READ) == 0) { - if (tmtab.b_errcnt) - cmd |= WIRG; + if (um->um_tab.b_errcnt) + cmd |= TM_WIRG; else - cmd |= WCOM; + cmd |= TM_WCOM; } else - cmd |= RCOM; - cmd |= (tm_ubinfo >> 12) & 0x30; - tmtab.b_active = SIO; - TMADDR->tmba = tm_ubinfo; - TMADDR->tmcs = cmd; + cmd |= TM_RCOM; + um->um_tab.b_active = SIO; + um->um_cmd = cmd; +#ifdef notdef + if (tmreverseop(sc->sc_lastcmd)) + while (addr->tmer & TM_SDWN) + tmgapsdcnt++; + sc->sc_lastcmd = TM_RCOM; /* will serve */ +#endif + ubago(ui); return; } - tmtab.b_active = SSEEK; + /* + * Block tape positioned incorrectly; + * seek forwards or backwards to the correct spot. + */ + um->um_tab.b_active = SSEEK; if (blkno < dbtofsb(bp->b_blkno)) { - cmd |= SFORW; - TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno); + bp->b_command = TM_SFORW; + addr->tmbc = blkno - dbtofsb(bp->b_blkno); } else { - cmd |= SREV; - TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno; + bp->b_command = TM_SREV; + addr->tmbc = dbtofsb(bp->b_blkno) - blkno; } - TMADDR->tmcs = cmd; +dobpcmd: +#ifdef notdef + if (tmreverseop(sc->sc_lastcmd) != tmreverseop(bp->b_command)) + while (addr->tmer & TM_SDWN) + tmgapsdcnt++; + sc->sc_lastcmd = bp->b_command; +#endif + addr->tmcs = (cmd | bp->b_command); return; next: - if (tm_ubinfo != 0) { - ubafree(tm_ubinfo); - tm_ubinfo = 0; - } - tmtab.b_actf = bp->av_forw; + /* + * Done with this operation due to error or + * the fact that it doesn't do anything. + * Release UBA resources (if any), dequeue + * the transfer and continue processing this slave. + */ + if (um->um_ubinfo) + ubadone(um); + um->um_tab.b_errcnt = 0; + dp->b_actf = bp->av_forw; iodone(bp); goto loop; } -tmintr() +/* + * The UNIBUS resources we needed have been + * allocated to us; start the device. + */ +tmdgo(um) + register struct uba_minfo *um; +{ + register struct device *addr = (struct device *)um->um_addr; + + addr->tmba = um->um_ubinfo; + addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30); +} + +/* + * Tm interrupt routine. + */ +/*ARGSUSED*/ +tmintr(tm11) + int tm11; { + struct buf *dp; register struct buf *bp; + register struct uba_minfo *um = tmminfo[tm11]; + register struct device *addr = (struct device *)tmdinfo[tm11]->ui_addr; + register struct tm_softc *sc; + int unit; register state; - if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) { - t_flags &= ~WAITREW; - wakeup((caddr_t)&t_flags); + /* + * If last command was a rewind, and tape is still + * rewinding, wait for the rewind complete interrupt. + */ + if (um->um_tab.b_active == SREW) { + um->um_tab.b_active = SCOM; + if (addr->tmer&TM_RWS) + return; } - if ((bp = tmtab.b_actf) == NULL) + /* + * An operation completed... record status + */ + if ((dp = um->um_tab.b_actf) == NULL) return; - t_dsreg = TMADDR->tmcs; - t_erreg = TMADDR->tmer; - t_resid = TMADDR->tmbc; + bp = dp->b_actf; + unit = TMUNIT(bp->b_dev); + sc = &tm_softc[unit]; + sc->sc_dsreg = addr->tmcs; + sc->sc_erreg = addr->tmer; + sc->sc_resid = addr->tmbc; if ((bp->b_flags & B_READ) == 0) - t_flags |= LASTIOW; - state = tmtab.b_active; - tmtab.b_active = 0; - if (TMADDR->tmcs&ERROR) { - while(TMADDR->tmer & SDWN) + sc->sc_lastiow = 1; + state = um->um_tab.b_active; + um->um_tab.b_active = 0; + /* + * Check for errors. + */ + if (addr->tmcs&TM_ERR) { + while (addr->tmer & TM_SDWN) ; /* await settle down */ - if (TMADDR->tmer&EOF) { - tmseteof(bp); /* set blkno and nxrec */ - state = SCOM; - TMADDR->tmbc = -bp->b_bcount; - goto errout; + /* + * If we hit the end of the tape update our position. + */ + if (addr->tmer&TM_EOF) { + tmseteof(bp); /* set blkno and nxrec */ + state = SCOM; /* force completion */ + /* + * Stuff bc so it will be unstuffed correctly + * later to get resid. + */ + addr->tmbc = -bp->b_bcount; + goto opdone; } - if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE) - goto out; - if ((TMADDR->tmer&HARD)==0 && state==SIO) { - if (++tmtab.b_errcnt < 7) { - if((TMADDR->tmer&SOFT) == NXM) - printf("TM UBA late error\n"); - else - t_blkno += 2; /* ???????? */ - if (tm_ubinfo) { - ubafree(tm_ubinfo); - tm_ubinfo = 0; - } - tmstart(); - return; + /* + * If we were reading and the only error was that the + * record was to long, then we don't consider this an error. + */ + if ((bp->b_flags&B_READ) && + (addr->tmer&(TM_HARD|TM_SOFT)) == TM_RLE) + goto ignoreerr; + /* + * If error is not hard, and this was an i/o operation + * retry up to 8 times. + */ + if ((addr->tmer&TM_HARD)==0 && state==SIO) { + if (++um->um_tab.b_errcnt < 7) { + sc->sc_blkno++; + ubadone(um); + goto opcont; } - } else if (t_openf>0 && bp != &rtmbuf) - t_openf = -1; - deverror(bp, t_erreg, t_dsreg); + } else + /* + * Hard or non-i/o errors on non-raw tape + * cause it to close. + */ + if (sc->sc_openf>0 && bp != &rtmbuf[unit]) + sc->sc_openf = -1; + /* + * Couldn't recover error + */ + printf("te%d: hard error bn%d er=%b\n", minor(bp->b_dev)&03, + bp->b_blkno, sc->sc_erreg, TMEREG_BITS); bp->b_flags |= B_ERROR; - state = SIO; + goto opdone; } -out: + /* + * Advance tape control FSM. + */ +ignoreerr: switch (state) { case SIO: - t_blkno++; - /* fall into ... */ + /* + * Read/write increments tape block number + */ + sc->sc_blkno++; + goto opdone; case SCOM: - if (bp == &ctmbuf) { - switch (bp->b_command) { - case SFORW: - t_blkno -= bp->b_repcnt; - break; + /* + * Unless special operation, op completed. + */ + if (bp != &ctmbuf[unit]) + goto opdone; + /* + * Operation on block device... + * iterate operations which don't repeat + * for themselves in the hardware; for forward/ + * backward space record update the current position. + */ + switch (bp->b_command) { + + case TM_SFORW: + sc->sc_blkno -= bp->b_repcnt; + goto opdone; + + case TM_SREV: + sc->sc_blkno += bp->b_repcnt; + goto opdone; - case SREV: - t_blkno += bp->b_repcnt; - break; - - default: - if (++bp->b_repcnt < 0) { - tmstart(); /* continue */ - return; - } - } - } -errout: - tmtab.b_errcnt = 0; - tmtab.b_actf = bp->av_forw; - bp->b_resid = -TMADDR->tmbc; - if (tm_ubinfo != 0) { - ubafree(tm_ubinfo); - tm_ubinfo = 0; + default: + if (++bp->b_repcnt < 0) + goto opcont; + goto opdone; } - iodone(bp); - break; case SSEEK: - t_blkno = dbtofsb(bp->b_blkno); - break; + sc->sc_blkno = dbtofsb(bp->b_blkno); + goto opcont; default: - return; + panic("tmintr"); + } +opdone: + /* + * Reset error count and remove + * from device queue. + */ + um->um_tab.b_errcnt = 0; + dp->b_actf = bp->av_forw; + bp->b_resid = -addr->tmbc; + ubadone(um); + iodone(bp); + /* + * Circulate slave to end of controller + * queue to give other slaves a chance. + */ + um->um_tab.b_actf = dp->b_forw; + if (dp->b_actf) { + dp->b_forw = NULL; + 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; } - tmstart(); + if (um->um_tab.b_actf == 0) + return; +opcont: + tmstart(um); } tmseteof(bp) register struct buf *bp; { + register int unit = TMUNIT(bp->b_dev); + register struct device *addr = + (struct device *)tmdinfo[unit]->ui_addr; + register struct tm_softc *sc = &tm_softc[unit]; - if (bp == &ctmbuf) { - if (t_blkno > dbtofsb(bp->b_blkno)) { + if (bp == &ctmbuf[unit]) { + if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { /* reversing */ - t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc; - t_blkno = t_nxrec; + sc->sc_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc; + sc->sc_blkno = sc->sc_nxrec; } else { /* spacing forward */ - t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc; - t_nxrec = t_blkno - 1; + sc->sc_blkno = dbtofsb(bp->b_blkno) + addr->tmbc; + sc->sc_nxrec = sc->sc_blkno - 1; } return; } /* eof on read */ - t_nxrec = dbtofsb(bp->b_blkno); + sc->sc_nxrec = dbtofsb(bp->b_blkno); } tmread(dev) + dev_t dev; { tmphys(dev); - physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); + physio(tmstrategy, &rtmbuf[TMUNIT(dev)], dev, B_READ, minphys); } tmwrite(dev) + dev_t dev; { tmphys(dev); - physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); + physio(tmstrategy, &rtmbuf[TMUNIT(dev)], dev, B_WRITE, minphys); } tmphys(dev) + dev_t dev; { register daddr_t a; + register struct tm_softc *sc = &tm_softc[TMUNIT(dev)]; a = dbtofsb(u.u_offset >> 9); - t_blkno = a; - t_nxrec = a + 1; + sc->sc_blkno = a; + sc->sc_nxrec = a + 1; +} + +tmreset(uban) + int uban; +{ + register struct uba_minfo *um; + register tm11, unit; + register struct uba_dinfo *ui; + register struct buf *dp; + + for (tm11 = 0; tm11 < NTM; tm11++) { + if ((um = tmminfo[tm11]) == 0 || um->um_alive == 0 || + um->um_ubanum != uban) + continue; + printf(" tm%d", tm11); + um->um_tab.b_active = 0; + um->um_tab.b_actf = um->um_tab.b_actl = 0; + if (um->um_ubinfo) { + printf("<%d>", (um->um_ubinfo>>28)&0xf); + ubadone(um); + } + ((struct device *)(um->um_addr))->tmcs = TM_DCLR; + for (unit = 0; unit < NTE; unit++) { + if ((ui = tmdinfo[unit]) == 0) + continue; + if (ui->ui_alive == 0) + continue; + dp = &tmutab[unit]; + dp->b_active = 0; + dp->b_forw = 0; + 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; + tm_softc[unit].sc_openf = -1; + } + tmstart(um); + } } /*ARGSUSED*/ @@ -440,21 +689,29 @@ tmioctl(dev, cmd, addr, flag) caddr_t addr; dev_t dev; { + int unit = TMUNIT(dev); + register struct tm_softc *sc = &tm_softc[unit]; + register struct buf *bp = &ctmbuf[unit]; register callcount; int fcount; struct mtop mtop; struct mtget mtget; /* we depend of the values and order of the MT codes here */ - static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL}; + static tmops[] = + {TM_WEOF,TM_SFORW,TM_SREV,TM_SFORW,TM_SREV,TM_REW,TM_OFFL,TM_SENSE}; - switch(cmd) { + switch (cmd) { case MTIOCTOP: /* tape operation */ if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { u.u_error = EFAULT; return; } switch(mtop.mt_op) { - case MTWEOF: case MTFSF: case MTBSF: + case MTWEOF: + callcount = mtop.mt_count; + fcount = 1; + break; + case MTFSF: case MTBSF: callcount = mtop.mt_count; fcount = INF; break; @@ -462,7 +719,7 @@ tmioctl(dev, cmd, addr, flag) callcount = 1; fcount = mtop.mt_count; break; - case MTREW: case MTOFFL: + case MTREW: case MTOFFL: case MTNOP: callcount = 1; fcount = 1; break; @@ -470,24 +727,26 @@ tmioctl(dev, cmd, addr, flag) u.u_error = ENXIO; return; } - if (callcount <= 0 || fcount <= 0) + if (callcount <= 0 || fcount <= 0) { u.u_error = ENXIO; - else while (--callcount >= 0) { - tcommand(dev, tmops[mtop.mt_op], fcount); + return; + } + while (--callcount >= 0) { + tmcommand(dev, tmops[mtop.mt_op], fcount); if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && - ctmbuf.b_resid) { + bp->b_resid) { u.u_error = EIO; break; } - if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) + if ((bp->b_flags&B_ERROR) || sc->sc_erreg&TM_BOT) break; } - geterror(&ctmbuf); + geterror(bp); return; case MTIOCGET: - mtget.mt_dsreg = t_dsreg; - mtget.mt_erreg = t_erreg; - mtget.mt_resid = t_resid; + mtget.mt_dsreg = sc->sc_dsreg; + mtget.mt_erreg = sc->sc_erreg; + mtget.mt_resid = sc->sc_resid; if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) u.u_error = EFAULT; return; @@ -498,67 +757,79 @@ tmioctl(dev, cmd, addr, flag) #define DBSIZE 20 -twall(start, num) - int start, num; +tmdump() { -#if VAX==780 - register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; -#endif - int blk; - - TMPHYS->tmcs = DCLR | GO; -#if VAX==780 - up->uba_cr = ADINIT; - up->uba_cr = IFS|BRIE|USEFIE|SUEFIE; - while ((up->uba_cnfgr & UBIC) == 0) - ; + register struct uba_dinfo *ui; + register struct uba_regs *up; + register struct device *addr; + int blk, num; + int start; + + start = 0; + num = maxfree; +#define phys(a,b) ((b)((int)(a)&0x7fffffff)) + if (tmdinfo[0] == 0) + return (ENXIO); + ui = phys(tmdinfo[0], struct uba_dinfo *); + up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; +#if VAX780 + if (cpu == VAX_780) + ubainit(up); #endif + DELAY(1000000); + addr = (struct device *)ui->ui_physaddr; + tmwait(addr); + addr->tmcs = TM_DCLR | TM_GO; while (num > 0) { blk = num > DBSIZE ? DBSIZE : num; - tmdwrite(start, blk); + tmdwrite(start, blk, addr, up); start += blk; num -= blk; } - ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE; + tmeof(addr); + tmeof(addr); + tmwait(addr); + if (addr->tmcs&TM_ERR) + return (EIO); + addr->tmcs = TM_REW | TM_GO; + tmwait(addr); + return (0); } -tmdwrite(buf, num) -register buf, num; +tmdwrite(dbuf, num, addr, up) + register dbuf, num; + register struct device *addr; + struct uba_regs *up; { - register int *io, npf; + register struct pte *io; + register int npf; - tmwait(); - ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE; - io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; + tmwait(addr); + io = up->uba_map; npf = num+1; while (--npf != 0) - *io++ = (int)(buf++ | (1<<21) | MRV); - *io = 0; - TMPHYS->tmbc = -(num*NBPG); - TMPHYS->tmba = 0; - TMPHYS->tmcs = WCOM | GO | D800; + *(int *)io++ = (dbuf++ | (1<tmbc = -(num*NBPG); + addr->tmba = 0; + addr->tmcs = TM_WCOM | TM_GO; } -tmwait() +tmwait(addr) + register struct device *addr; { register s; do - s = TMPHYS->tmcs; - while ((s & CUR) == 0); -} - -tmrewind() -{ - - tmwait(); - TMPHYS->tmcs = REW | GO; + s = addr->tmcs; + while ((s & TM_CUR) == 0); } -tmeof() +tmeof(addr) + struct device *addr; { - tmwait(); - TMPHYS->tmcs = WEOF | GO | D800; + tmwait(addr); + addr->tmcs = TM_WEOF | TM_GO; } #endif