xref: /original-bsd/sys/vax/mba/ht.c (revision 889e8222)
1*889e8222Sbostic /*-
2*889e8222Sbostic  * Copyright (c) 1982, 1986 The Regents of the University of California.
3*889e8222Sbostic  * All rights reserved.
404edf258Smckusick  *
5*889e8222Sbostic  * %sccs.include.proprietary.c%
6*889e8222Sbostic  *
7*889e8222Sbostic  *	@(#)ht.c	7.14 (Berkeley) 05/08/91
804edf258Smckusick  */
95351d98cSwnj 
1032c45393Swnj #include "tu.h"
118a77158cSbill #if NHT > 0
123f1fa103Sbill /*
13dba4e647Swnj  * TM03/TU?? tape driver
14df5b9483Swnj  *
15df5b9483Swnj  * TODO:
164d89bee9Swnj  *	cleanup messages on errors
17df5b9483Swnj  *	test ioctl's
18df5b9483Swnj  *	see how many rewind interrups we get if we kick when not at BOT
194d89bee9Swnj  *	fixup rle error on block tape code
203f1fa103Sbill  */
21b079d642Sbostic #include "sys/param.h"
22b079d642Sbostic #include "sys/systm.h"
23b079d642Sbostic #include "sys/buf.h"
24b079d642Sbostic #include "sys/conf.h"
25b079d642Sbostic #include "sys/file.h"
26b079d642Sbostic #include "sys/user.h"
27b079d642Sbostic #include "sys/proc.h"
28b079d642Sbostic #include "sys/map.h"
29b079d642Sbostic #include "sys/ioctl.h"
30b079d642Sbostic #include "sys/mtio.h"
31b079d642Sbostic #include "sys/cmap.h"
32b079d642Sbostic #include "sys/tty.h"
33b079d642Sbostic #include "sys/syslog.h"
34b079d642Sbostic #include "sys/tprintf.h"
353f1fa103Sbill 
36b079d642Sbostic #include "../include/pte.h"
37b079d642Sbostic #include "../include/cpu.h"
38eed77dbbSbloom #include "mbareg.h"
39eed77dbbSbloom #include "mbavar.h"
40eed77dbbSbloom #include "htreg.h"
413f1fa103Sbill 
42dba4e647Swnj struct	buf	chtbuf[NHT];
433f1fa103Sbill 
44dba4e647Swnj short	httypes[] =
45380f079fSwnj 	{ MBDT_TM03, MBDT_TE16, MBDT_TU45, MBDT_TU77, 0 };
4632c45393Swnj struct	mba_device *htinfo[NHT];
4781d4a72fSkarels struct	mba_slave *tuinfo[NTU];
488e572de3Swnj int	htattach(), htslave(), htustart(), htndtint(), htdtint();
49dba4e647Swnj struct	mba_driver htdriver =
5032c45393Swnj     { htattach, htslave, htustart, 0, htdtint, htndtint,
5132c45393Swnj       httypes, "ht", "tu", htinfo };
523f1fa103Sbill 
53dba4e647Swnj #define MASKREG(r)	((r) & 0xffff)
543f1fa103Sbill 
55dba4e647Swnj /* bits in minor device */
5632c45393Swnj #define	TUUNIT(dev)	(minor(dev)&03)
57dba4e647Swnj #define	H_NOREWIND	04
585575e211Skarels #define	H_DENS(dev)	((minor(dev) >> 3) & 03)
593f1fa103Sbill 
60170c2372Sbostic #define HTUNIT(dev)	(tuinfo[TUUNIT(dev)]->ms_ctlr)
6132c45393Swnj 
62dba4e647Swnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
63dba4e647Swnj 
64df5b9483Swnj struct	tu_softc {
65dba4e647Swnj 	char	sc_openf;
66dba4e647Swnj 	char	sc_flags;
67dba4e647Swnj 	daddr_t	sc_blkno;
68dba4e647Swnj 	daddr_t	sc_nxrec;
69dba4e647Swnj 	u_short	sc_erreg;
70dba4e647Swnj 	u_short	sc_dsreg;
71dba4e647Swnj 	short	sc_resid;
72dba4e647Swnj 	short	sc_dens;
73b079d642Sbostic 	tpr_t	sc_tpr;		/* tprintf handle for errors to user */
74dd03e160Skarels 	int	sc_blks;	/* number of I/O operations since open */
75dd03e160Skarels 	int	sc_softerrs;	/* number of soft I/O errors since open */
76df5b9483Swnj } tu_softc[NTU];
77dba4e647Swnj 
78dba4e647Swnj /*
79dba4e647Swnj  * Bits for sc_flags.
80dba4e647Swnj  */
81dba4e647Swnj #define	H_WRITTEN 1	/* last operation was a write */
82dba4e647Swnj #define H_ERASED  2	/* last write retry was an erase gap */
83dba4e647Swnj #define H_REWIND  4	/* last unit start was a rewind */
84dba4e647Swnj 
854d89bee9Swnj char	hter_bits[] = HTER_BITS;
864d89bee9Swnj char	htds_bits[] = HTDS_BITS;
874d89bee9Swnj 
88dba4e647Swnj /*ARGSUSED*/
8932c45393Swnj htattach(mi)
9032c45393Swnj 	struct mba_device *mi;
91dba4e647Swnj {
92dba4e647Swnj 
93dba4e647Swnj }
943f1fa103Sbill 
9530f13f65Skre htslave(mi, ms, sn)
9632c45393Swnj 	struct mba_device *mi;
9732c45393Swnj 	struct mba_slave *ms;
9830f13f65Skre 	int sn;
9932c45393Swnj {
1002532499eSwnj 	register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
10132c45393Swnj 
10230f13f65Skre 	htaddr->httc = sn;
1032532499eSwnj 	if (htaddr->htdt & HTDT_SPR) {
10481d4a72fSkarels 		tuinfo[ms->ms_unit] = ms;
1052532499eSwnj 		return (1);
1062532499eSwnj 	} else
1072532499eSwnj 		return (0);
10832c45393Swnj }
10932c45393Swnj 
1105575e211Skarels int	htdens[4] = { HTTC_800BPI, HTTC_1600BPI, HTTC_6250BPI, HTTC_800BPI };
1115575e211Skarels 
htopen(dev,flag)1123f1fa103Sbill htopen(dev, flag)
113dba4e647Swnj 	dev_t dev;
114dba4e647Swnj 	int flag;
1153f1fa103Sbill {
116df5b9483Swnj 	register int tuunit;
117df5b9483Swnj 	register struct tu_softc *sc;
118170c2372Sbostic 	register struct mba_slave *ms;
119f8bb811cSwnj 	int olddens, dens;
1203f1fa103Sbill 
121df5b9483Swnj 	tuunit = TUUNIT(dev);
122170c2372Sbostic 	if (tuunit >= NTU || (ms = tuinfo[tuunit]) == NULL ||
123170c2372Sbostic 	    ms->ms_alive == 0 || htinfo[ms->ms_ctlr]->mi_alive == 0)
1241502981eSroot 		return (ENXIO);
1253ef931cbSkarels 	if ((sc = &tu_softc[tuunit])->sc_openf)
1263ef931cbSkarels 		return (EBUSY);
127dd03e160Skarels 	sc->sc_openf = 1;
128f8bb811cSwnj 	olddens = sc->sc_dens;
129170c2372Sbostic 	dens = sc->sc_dens = htdens[H_DENS(dev)] | HTTC_PDP11 | ms->ms_slave;
130f8bb811cSwnj 	htcommand(dev, HT_SENSE, 1);
131f8bb811cSwnj 	sc->sc_dens = olddens;
13254ce6e34Sroot 	if ((sc->sc_dsreg & HTDS_MOL) == 0) {
133dd03e160Skarels 		sc->sc_openf = 0;
134a6b49dafSroot 		uprintf("tu%d: not online\n", tuunit);
1351502981eSroot 		return (EIO);
13654ce6e34Sroot 	}
13754ce6e34Sroot 	if ((flag&FWRITE) && (sc->sc_dsreg&HTDS_WRL)) {
138dd03e160Skarels 		sc->sc_openf = 0;
139a6b49dafSroot 		uprintf("tu%d: no write ring\n", tuunit);
1401502981eSroot 		return (EIO);
14154ce6e34Sroot 	}
14254ce6e34Sroot 	if ((sc->sc_dsreg & HTDS_BOT) == 0 && (flag&FWRITE) &&
1431ea522abSwnj 	    dens != sc->sc_dens) {
144dd03e160Skarels 		sc->sc_openf = 0;
145a6b49dafSroot 		uprintf("tu%d: can't change density in mid-tape\n", tuunit);
1461502981eSroot 		return (EIO);
147dba4e647Swnj 	}
148dba4e647Swnj 	sc->sc_blkno = (daddr_t)0;
149dba4e647Swnj 	sc->sc_nxrec = INF;
150dba4e647Swnj 	sc->sc_flags = 0;
151df5b9483Swnj 	sc->sc_dens = dens;
152dd03e160Skarels 	sc->sc_blks = 0;
153dd03e160Skarels 	sc->sc_softerrs = 0;
154dbbf5920Storek 	sc->sc_tpr = tprintf_open();
1551502981eSroot 	return (0);
1563f1fa103Sbill }
1573f1fa103Sbill 
htclose(dev,flag)1583f1fa103Sbill htclose(dev, flag)
159dba4e647Swnj 	register dev_t dev;
160dba4e647Swnj 	register flag;
1613f1fa103Sbill {
162df5b9483Swnj 	register struct tu_softc *sc = &tu_softc[TUUNIT(dev)];
1633f1fa103Sbill 
164dba4e647Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN))) {
165dba4e647Swnj 		htcommand(dev, HT_WEOF, 1);
166dba4e647Swnj 		htcommand(dev, HT_WEOF, 1);
167dba4e647Swnj 		htcommand(dev, HT_SREV, 1);
1683f1fa103Sbill 	}
169dba4e647Swnj 	if ((minor(dev)&H_NOREWIND) == 0)
170dba4e647Swnj 		htcommand(dev, HT_REW, 0);
171dd03e160Skarels 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
172dd03e160Skarels 		log(LOG_INFO, "tu%d: %d soft errors in %d blocks\n",
173dd03e160Skarels 		    TUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
174dbbf5920Storek 	tprintf_close(sc->sc_tpr);
175dba4e647Swnj 	sc->sc_openf = 0;
176b413ba51Skarels 	return (0);
1773f1fa103Sbill }
1783f1fa103Sbill 
htcommand(dev,com,count)179dba4e647Swnj htcommand(dev, com, count)
180dba4e647Swnj 	dev_t dev;
181dba4e647Swnj 	int com, count;
1823f1fa103Sbill {
1833f1fa103Sbill 	register struct buf *bp;
1840f92fdc5Sroot 	register int s;
1853f1fa103Sbill 
186dba4e647Swnj 	bp = &chtbuf[HTUNIT(dev)];
1870f92fdc5Sroot 	s = spl5();
1883f1fa103Sbill 	while (bp->b_flags&B_BUSY) {
1891ea522abSwnj 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
19032c45393Swnj 			break;
1913f1fa103Sbill 		bp->b_flags |= B_WANTED;
1923f1fa103Sbill 		sleep((caddr_t)bp, PRIBIO);
1933f1fa103Sbill 	}
194eec047c2Swnj 	bp->b_flags = B_BUSY|B_READ;
1950f92fdc5Sroot 	splx(s);
1963f1fa103Sbill 	bp->b_dev = dev;
197dba4e647Swnj 	bp->b_command = com;
198dba4e647Swnj 	bp->b_repcnt = count;
1993f1fa103Sbill 	bp->b_blkno = 0;
2003f1fa103Sbill 	htstrategy(bp);
201dba4e647Swnj 	if (count == 0)
202dba4e647Swnj 		return;
2033f1fa103Sbill 	iowait(bp);
2043f1fa103Sbill 	if (bp->b_flags&B_WANTED)
2053f1fa103Sbill 		wakeup((caddr_t)bp);
206dba4e647Swnj 	bp->b_flags &= B_ERROR;
2073f1fa103Sbill }
2083f1fa103Sbill 
htstrategy(bp)2093f1fa103Sbill htstrategy(bp)
2103f1fa103Sbill 	register struct buf *bp;
2113f1fa103Sbill {
212df5b9483Swnj 	register struct mba_device *mi = htinfo[HTUNIT(bp->b_dev)];
213dba4e647Swnj 	register struct buf *dp;
2140f92fdc5Sroot 	register int s;
2153f1fa103Sbill 
2163f1fa103Sbill 	bp->av_forw = NULL;
217dba4e647Swnj 	dp = &mi->mi_tab;
2180f92fdc5Sroot 	s = spl5();
219dba4e647Swnj 	if (dp->b_actf == NULL)
220dba4e647Swnj 		dp->b_actf = bp;
2213f1fa103Sbill 	else
222dba4e647Swnj 		dp->b_actl->av_forw = bp;
223dba4e647Swnj 	dp->b_actl = bp;
224dba4e647Swnj 	if (dp->b_active == 0)
225dba4e647Swnj 		mbustart(mi);
2260f92fdc5Sroot 	splx(s);
2273f1fa103Sbill }
2283f1fa103Sbill 
htustart(mi)229dba4e647Swnj htustart(mi)
23032c45393Swnj 	register struct mba_device *mi;
2313f1fa103Sbill {
232dba4e647Swnj 	register struct htdevice *htaddr =
233dba4e647Swnj 	    (struct htdevice *)mi->mi_drv;
234dba4e647Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
235df5b9483Swnj 	register struct tu_softc *sc = &tu_softc[TUUNIT(bp->b_dev)];
2363f1fa103Sbill 	daddr_t blkno;
2373f1fa103Sbill 
238dba4e647Swnj 	htaddr->httc = sc->sc_dens;
239daa303d3Skarels #ifdef	notdef
240daa303d3Skarels 	/* unneeded, may hang controller */
241380f079fSwnj 	if (bp == &chtbuf[HTUNIT(bp->b_dev)] && bp->b_command == HT_SENSE) {
2421ea522abSwnj 		htaddr->htcs1 = HT_SENSE|HT_GO;
2431ea522abSwnj 		mbclrattn(mi);
2441ea522abSwnj 	}
245daa303d3Skarels #endif
246dba4e647Swnj 	sc->sc_dsreg = htaddr->htds;
247dba4e647Swnj 	sc->sc_erreg = htaddr->hter;
248dba4e647Swnj 	sc->sc_resid = htaddr->htfc;
249dba4e647Swnj 	sc->sc_flags &= ~(H_WRITTEN|H_REWIND);
250dba4e647Swnj 	if ((htaddr->htdt & HTDT_SPR) == 0 || (htaddr->htds & HTDS_MOL) == 0)
251dba4e647Swnj 		if (sc->sc_openf > 0)
252dba4e647Swnj 			sc->sc_openf = -1;
253dba4e647Swnj 	if (sc->sc_openf < 0) {
254dba4e647Swnj 		bp->b_flags |= B_ERROR;
255dba4e647Swnj 		return (MBU_NEXT);
256dba4e647Swnj 	}
257df5b9483Swnj 	if (bp != &chtbuf[HTUNIT(bp->b_dev)]) {
258170c2372Sbostic 		/* transfer: check positioning */
259170c2372Sbostic 		if (bp->b_flags & B_RAW) {
260170c2372Sbostic 			/* raw transfer: record position for retry */
261170c2372Sbostic 			if (mi->mi_tab.b_errcnt == 0) {
262170c2372Sbostic 				sc->sc_blkno = bdbtofsb(bp->b_blkno);
263170c2372Sbostic 				sc->sc_nxrec = sc->sc_blkno + 1;
264170c2372Sbostic 			}
265170c2372Sbostic 		} else {
266300ae12dSsam 			if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
267dba4e647Swnj 				bp->b_flags |= B_ERROR;
268dba4e647Swnj 				bp->b_error = ENXIO;
2695351d98cSwnj 				return (MBU_NEXT);
270df5b9483Swnj 			}
271300ae12dSsam 			if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
272dba4e647Swnj 			    bp->b_flags&B_READ) {
273dba4e647Swnj 				bp->b_resid = bp->b_bcount;
274dba4e647Swnj 				clrbuf(bp);
2755351d98cSwnj 				return (MBU_NEXT);
276df5b9483Swnj 			}
277df5b9483Swnj 			if ((bp->b_flags&B_READ)==0)
278300ae12dSsam 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
279170c2372Sbostic 		}
2803f1fa103Sbill 	} else {
2815351d98cSwnj 		if (bp->b_command == HT_SENSE)
282dba4e647Swnj 			return (MBU_NEXT);
283dba4e647Swnj 		if (bp->b_command == HT_REW)
284dba4e647Swnj 			sc->sc_flags |= H_REWIND;
285dba4e647Swnj 		else
286dba4e647Swnj 			htaddr->htfc = -bp->b_bcount;
287dba4e647Swnj 		htaddr->htcs1 = bp->b_command|HT_GO;
288dba4e647Swnj 		return (MBU_STARTED);
2893f1fa103Sbill 	}
290300ae12dSsam 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
291dba4e647Swnj 		htaddr->htfc = -bp->b_bcount;
2923f1fa103Sbill 		if ((bp->b_flags&B_READ) == 0) {
293df5b9483Swnj 			if (mi->mi_tab.b_errcnt) {
294df5b9483Swnj 				if ((sc->sc_flags & H_ERASED) == 0) {
295dba4e647Swnj 					sc->sc_flags |= H_ERASED;
296dba4e647Swnj 					htaddr->htcs1 = HT_ERASE | HT_GO;
297dba4e647Swnj 					return (MBU_STARTED);
2983f1fa103Sbill 				}
299df5b9483Swnj 				sc->sc_flags &= ~H_ERASED;
300df5b9483Swnj 			}
301dba4e647Swnj 			if (htaddr->htds & HTDS_EOT) {
302dba4e647Swnj 				bp->b_resid = bp->b_bcount;
3033985bb71Swnj 				bp->b_flags |= B_ERROR;
304dba4e647Swnj 				return (MBU_NEXT);
305dba4e647Swnj 			}
306dba4e647Swnj 		}
307dba4e647Swnj 		return (MBU_DODATA);
308dba4e647Swnj 	}
309300ae12dSsam 	if (blkno < bdbtofsb(bp->b_blkno)) {
310300ae12dSsam 		htaddr->htfc = blkno - bdbtofsb(bp->b_blkno);
311dba4e647Swnj 		htaddr->htcs1 = HT_SFORW|HT_GO;
3123f1fa103Sbill 	} else {
313300ae12dSsam 		htaddr->htfc = bdbtofsb(bp->b_blkno) - blkno;
314dba4e647Swnj 		htaddr->htcs1 = HT_SREV|HT_GO;
3153f1fa103Sbill 	}
316dba4e647Swnj 	return (MBU_STARTED);
317dba4e647Swnj }
3183f1fa103Sbill 
htdtint(mi,mbsr)319df5b9483Swnj htdtint(mi, mbsr)
32032c45393Swnj 	register struct mba_device *mi;
321df5b9483Swnj 	int mbsr;
322dba4e647Swnj {
323dba4e647Swnj 	register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
324dba4e647Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
325df5b9483Swnj 	register struct tu_softc *sc;
3265351d98cSwnj 	int ds, er, mbs;
327dba4e647Swnj 
328df5b9483Swnj 	sc = &tu_softc[TUUNIT(bp->b_dev)];
329dba4e647Swnj 	ds = sc->sc_dsreg = MASKREG(htaddr->htds);
330dba4e647Swnj 	er = sc->sc_erreg = MASKREG(htaddr->hter);
331dba4e647Swnj 	sc->sc_resid = MASKREG(htaddr->htfc);
332df5b9483Swnj 	mbs = mbsr;
333dba4e647Swnj 	sc->sc_blkno++;
334dba4e647Swnj 	if((bp->b_flags & B_READ) == 0)
335dba4e647Swnj 		sc->sc_flags |= H_WRITTEN;
336df5b9483Swnj 	if ((ds&(HTDS_ERR|HTDS_MOL)) != HTDS_MOL || mbs & MBSR_EBITS) {
337dba4e647Swnj 		htaddr->htcs1 = HT_DCLR|HT_GO;
3385351d98cSwnj 		mbclrattn(mi);
339170c2372Sbostic 		if (bp->b_flags & B_RAW) {
340dba4e647Swnj 			er &= ~HTER_FCE;
341df5b9483Swnj 			mbs &= ~(MBSR_DTABT|MBSR_MBEXC);
342a79aec37Sroot 		}
343dba4e647Swnj 		if (bp->b_flags & B_READ && ds & HTDS_PES)
344dba4e647Swnj 			er &= ~(HTER_CSITM|HTER_CORCRC);
345df5b9483Swnj 		if (er&HTER_HARD || mbs&MBSR_EBITS || (ds&HTDS_MOL) == 0 ||
3465351d98cSwnj 		    er && ++mi->mi_tab.b_errcnt >= 7) {
347dba4e647Swnj 			if ((ds & HTDS_MOL) == 0 && sc->sc_openf > 0)
348dba4e647Swnj 				sc->sc_openf = -1;
3491ea522abSwnj 			if ((er&HTER_HARD) == HTER_FCE &&
3501ea522abSwnj 			    (mbs&MBSR_EBITS) == (MBSR_DTABT|MBSR_MBEXC) &&
3511ea522abSwnj 			    (ds&HTDS_MOL))
3521ea522abSwnj 				goto noprint;
353dbbf5920Storek 			tprintf(sc->sc_tpr,
354dbbf5920Storek 			    "tu%d: hard error bn%d mbsr=%b er=%b ds=%b\n",
35532c45393Swnj 			    TUUNIT(bp->b_dev), bp->b_blkno,
356df5b9483Swnj 			    mbsr, mbsr_bits,
3574d89bee9Swnj 			    sc->sc_erreg, hter_bits,
3584d89bee9Swnj 			    sc->sc_dsreg, htds_bits);
3591ea522abSwnj noprint:
360dba4e647Swnj 			bp->b_flags |= B_ERROR;
361dba4e647Swnj 			return (MBD_DONE);
3623f1fa103Sbill 		}
363dba4e647Swnj 		if (er)
364dba4e647Swnj 			return (MBD_RETRY);
365dba4e647Swnj 	}
366dba4e647Swnj 	bp->b_resid = 0;
367dd03e160Skarels 	sc->sc_blks++;
368dd03e160Skarels 	if (mi->mi_tab.b_errcnt)
369dd03e160Skarels 		sc->sc_softerrs++;
370dba4e647Swnj 	if (bp->b_flags & B_READ)
371dba4e647Swnj 		if (ds&HTDS_TM) {		/* must be a read, right? */
372dba4e647Swnj 			bp->b_resid = bp->b_bcount;
373300ae12dSsam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno);
374dba4e647Swnj 		} else if(bp->b_bcount > MASKREG(htaddr->htfc))
375dba4e647Swnj 			bp->b_resid = bp->b_bcount - MASKREG(htaddr->htfc);
376dba4e647Swnj 	return (MBD_DONE);
377dba4e647Swnj }
378dba4e647Swnj 
htndtint(mi)379dba4e647Swnj htndtint(mi)
38032c45393Swnj 	register struct mba_device *mi;
381dba4e647Swnj {
382dba4e647Swnj 	register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
383dba4e647Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
384df5b9483Swnj 	register struct tu_softc *sc;
385dba4e647Swnj 	int er, ds, fc;
386dba4e647Swnj 
387df5b9483Swnj 	ds = MASKREG(htaddr->htds);
388df5b9483Swnj 	er = MASKREG(htaddr->hter);
389df5b9483Swnj 	fc = MASKREG(htaddr->htfc);
390df5b9483Swnj 	if (er) {
391dba4e647Swnj 		htaddr->htcs1 = HT_DCLR|HT_GO;
3925351d98cSwnj 		mbclrattn(mi);
3935351d98cSwnj 	}
394df5b9483Swnj 	if (bp == 0)
395df5b9483Swnj 		return (MBN_SKIP);
396df5b9483Swnj 	sc = &tu_softc[TUUNIT(bp->b_dev)];
397df5b9483Swnj 	sc->sc_dsreg = ds;
398df5b9483Swnj 	sc->sc_erreg = er;
399df5b9483Swnj 	sc->sc_resid = fc;
400df5b9483Swnj 	if (bp == &chtbuf[HTUNIT(bp->b_dev)]) {
40164d0d3acSkarels 		switch ((int)bp->b_command) {
402df5b9483Swnj 		case HT_REWOFFL:
403dba4e647Swnj 			/* offline is on purpose; don't do anything special */
404dba4e647Swnj 			ds |= HTDS_MOL;
405df5b9483Swnj 			break;
406df5b9483Swnj 		case HT_SREV:
407df5b9483Swnj 			/* if backspace file hit bot, its not an error */
408df5b9483Swnj 		        if (er == (HTER_NEF|HTER_FCE) && ds&HTDS_BOT &&
409df5b9483Swnj 			    bp->b_repcnt == INF)
410dba4e647Swnj 				er &= ~HTER_NEF;
411df5b9483Swnj 			break;
412df5b9483Swnj 		}
413dba4e647Swnj 		er &= ~HTER_FCE;
414dba4e647Swnj 		if (er == 0)
415dba4e647Swnj 			ds &= ~HTDS_ERR;
416dba4e647Swnj 	}
417dba4e647Swnj 	if ((ds & (HTDS_ERR|HTDS_MOL)) != HTDS_MOL) {
418dba4e647Swnj 		if ((ds & HTDS_MOL) == 0 && sc->sc_openf > 0)
419dba4e647Swnj 			sc->sc_openf = -1;
420dbbf5920Storek 		tprintf(sc->sc_tpr, "tu%d: hard error bn%d er=%b ds=%b\n",
42132c45393Swnj 		    TUUNIT(bp->b_dev), bp->b_blkno,
4224d89bee9Swnj 		    sc->sc_erreg, hter_bits, sc->sc_dsreg, htds_bits);
423dba4e647Swnj 		bp->b_flags |= B_ERROR;
424dba4e647Swnj 		return (MBN_DONE);
425dba4e647Swnj 	}
426df5b9483Swnj 	if (bp == &chtbuf[HTUNIT(bp->b_dev)]) {
427dba4e647Swnj 		if (sc->sc_flags & H_REWIND)
428dba4e647Swnj 			return (ds & HTDS_BOT ? MBN_DONE : MBN_RETRY);
429dba4e647Swnj 		bp->b_resid = -sc->sc_resid;
430dba4e647Swnj 		return (MBN_DONE);
431dba4e647Swnj 	}
432dba4e647Swnj 	if (ds & HTDS_TM)
433300ae12dSsam 		if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
434300ae12dSsam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
435dba4e647Swnj 			sc->sc_blkno = sc->sc_nxrec;
436df5b9483Swnj 		} else {
437300ae12dSsam 			sc->sc_blkno = bdbtofsb(bp->b_blkno) + fc;
438dba4e647Swnj 			sc->sc_nxrec = sc->sc_blkno - 1;
439dba4e647Swnj 		}
440dba4e647Swnj 	else
441300ae12dSsam 		sc->sc_blkno = bdbtofsb(bp->b_blkno);
442dba4e647Swnj 	return (MBN_RETRY);
4433f1fa103Sbill }
4443f1fa103Sbill 
445dba4e647Swnj /*ARGSUSED*/
htioctl(dev,cmd,data,flag)4469e7b0143Ssam htioctl(dev, cmd, data, flag)
447dba4e647Swnj 	dev_t dev;
448dba4e647Swnj 	int cmd;
4499e7b0143Ssam 	caddr_t data;
450dba4e647Swnj 	int flag;
451dba4e647Swnj {
452df5b9483Swnj 	register struct tu_softc *sc = &tu_softc[TUUNIT(dev)];
453df5b9483Swnj 	register struct buf *bp = &chtbuf[HTUNIT(dev)];
454dba4e647Swnj 	register callcount;
455dbbf5920Storek 	int fcount;
4569e7b0143Ssam 	struct mtop *mtop;
4579e7b0143Ssam 	struct mtget *mtget;
458dba4e647Swnj 	/* we depend of the values and order of the MT codes here */
459dba4e647Swnj 	static htops[] =
460dba4e647Swnj    {HT_WEOF,HT_SFORW,HT_SREV,HT_SFORW,HT_SREV,HT_REW,HT_REWOFFL,HT_SENSE};
461dba4e647Swnj 
462dba4e647Swnj 	switch (cmd) {
4639e7b0143Ssam 
464dba4e647Swnj 	case MTIOCTOP:	/* tape operation */
4659e7b0143Ssam 		mtop = (struct mtop *)data;
4669e7b0143Ssam 		switch (mtop->mt_op) {
4679e7b0143Ssam 
468dba4e647Swnj 		case MTWEOF:
4699e7b0143Ssam 			callcount = mtop->mt_count;
470dba4e647Swnj 			fcount = 1;
471dba4e647Swnj 			break;
4729e7b0143Ssam 
473dba4e647Swnj 		case MTFSF: case MTBSF:
4749e7b0143Ssam 			callcount = mtop->mt_count;
475dba4e647Swnj 			fcount = INF;
476dba4e647Swnj 			break;
4779e7b0143Ssam 
478dba4e647Swnj 		case MTFSR: case MTBSR:
479dba4e647Swnj 			callcount = 1;
4809e7b0143Ssam 			fcount = mtop->mt_count;
481dba4e647Swnj 			break;
4829e7b0143Ssam 
483dba4e647Swnj 		case MTREW: case MTOFFL:
484dba4e647Swnj 			callcount = 1;
485dba4e647Swnj 			fcount = 1;
486dba4e647Swnj 			break;
4879e7b0143Ssam 
488dba4e647Swnj 		default:
4891502981eSroot 			return (ENXIO);
490dba4e647Swnj 		}
4911502981eSroot 		if (callcount <= 0 || fcount <= 0)
4921502981eSroot 			return (EINVAL);
493dba4e647Swnj 		while (--callcount >= 0) {
4949e7b0143Ssam 			htcommand(dev, htops[mtop->mt_op], fcount);
4959e7b0143Ssam 			if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
4961502981eSroot 			    bp->b_resid)
4971502981eSroot 				return (EIO);
498df5b9483Swnj 			if ((bp->b_flags&B_ERROR) || sc->sc_dsreg&HTDS_BOT)
499dba4e647Swnj 				break;
500dba4e647Swnj 		}
5011e9d36e0Ssklower 		if (bp->b_flags&B_ERROR)
502dbbf5920Storek 			return (bp->b_error ? bp->b_error : EIO);
503dbbf5920Storek 		return (0);
5049e7b0143Ssam 
505dba4e647Swnj 	case MTIOCGET:
5069e7b0143Ssam 		mtget = (struct mtget *)data;
5079e7b0143Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
5089e7b0143Ssam 		mtget->mt_erreg = sc->sc_erreg;
5099e7b0143Ssam 		mtget->mt_resid = sc->sc_resid;
5109e7b0143Ssam 		mtget->mt_type = MT_ISHT;
5111502981eSroot 		break;
5129e7b0143Ssam 
513dba4e647Swnj 	default:
5141502981eSroot 		return (ENXIO);
515dba4e647Swnj 	}
5161502981eSroot 	return (0);
517dba4e647Swnj }
5187a5c45e7Swnj 
5197a5c45e7Swnj #define	DBSIZE	20
5207a5c45e7Swnj 
htdump()521dba4e647Swnj htdump()
5227a5c45e7Swnj {
52332c45393Swnj 	register struct mba_device *mi;
524dba4e647Swnj 	register struct mba_regs *mp;
525dba4e647Swnj 	register struct htdevice *htaddr;
526dba4e647Swnj 	int blk, num;
527dba4e647Swnj 	int start;
5287a5c45e7Swnj 
529dba4e647Swnj 	start = 0;
530dba4e647Swnj 	num = maxfree;
531dba4e647Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
532dba4e647Swnj 	if (htinfo[0] == 0)
533dba4e647Swnj 		return (ENXIO);
53432c45393Swnj 	mi = phys(htinfo[0], struct mba_device *);
535dba4e647Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
5361ea522abSwnj 	mp->mba_cr = MBCR_IE;
537dba4e647Swnj 	htaddr = (struct htdevice *)&mp->mba_drv[mi->mi_drive];
538dba4e647Swnj 	htaddr->httc = HTTC_PDP11|HTTC_1600BPI;
539dba4e647Swnj 	htaddr->htcs1 = HT_DCLR|HT_GO;
5407a5c45e7Swnj 	while (num > 0) {
5417a5c45e7Swnj 		blk = num > DBSIZE ? DBSIZE : num;
542dba4e647Swnj 		htdwrite(start, blk, htaddr, mp);
543dba4e647Swnj 		start += blk;
5447a5c45e7Swnj 		num -= blk;
5457a5c45e7Swnj 	}
5461ea522abSwnj 	hteof(htaddr);
5471ea522abSwnj 	hteof(htaddr);
548dba4e647Swnj 	htwait(htaddr);
549380f079fSwnj 	if (htaddr->htds&HTDS_ERR)
5501ea522abSwnj 		return (EIO);
551dba4e647Swnj 	htaddr->htcs1 = HT_REW|HT_GO;
5528e572de3Swnj 	return (0);
5537a5c45e7Swnj }
5547a5c45e7Swnj 
htdwrite(dbuf,num,htaddr,mp)555dba4e647Swnj htdwrite(dbuf, num, htaddr, mp)
556dba4e647Swnj 	register dbuf, num;
557dba4e647Swnj 	register struct htdevice *htaddr;
558dba4e647Swnj 	struct mba_regs *mp;
5597a5c45e7Swnj {
560dba4e647Swnj 	register struct pte *io;
5617a5c45e7Swnj 	register int i;
5627a5c45e7Swnj 
563dba4e647Swnj 	htwait(htaddr);
564dba4e647Swnj 	io = mp->mba_map;
5657a5c45e7Swnj 	for (i = 0; i < num; i++)
566dba4e647Swnj 		*(int *)io++ = dbuf++ | PG_V;
567dba4e647Swnj 	htaddr->htfc = -(num*NBPG);
568dba4e647Swnj 	mp->mba_sr = -1;
569dba4e647Swnj 	mp->mba_bcr = -(num*NBPG);
570dba4e647Swnj 	mp->mba_var = 0;
571dba4e647Swnj 	htaddr->htcs1 = HT_WCOM|HT_GO;
5727a5c45e7Swnj }
5737a5c45e7Swnj 
574dba4e647Swnj htwait(htaddr)
575dba4e647Swnj 	struct htdevice *htaddr;
5767a5c45e7Swnj {
5777a5c45e7Swnj 	register s;
5787a5c45e7Swnj 
5797a5c45e7Swnj 	do
580dba4e647Swnj 		s = htaddr->htds;
581dba4e647Swnj 	while ((s & HTDS_DRY) == 0);
5827a5c45e7Swnj }
5837a5c45e7Swnj 
584dba4e647Swnj hteof(htaddr)
585dba4e647Swnj 	struct htdevice *htaddr;
5867a5c45e7Swnj {
5877a5c45e7Swnj 
588dba4e647Swnj 	htwait(htaddr);
589dba4e647Swnj 	htaddr->htcs1 = HT_WEOF|HT_GO;
5907a5c45e7Swnj }
5918a77158cSbill #endif
592