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