another non-working version
[unix-history] / usr / src / sys / vax / mba / ht.c
CommitLineData
66b4fb09 1#include "ht.h"
a5cc519e 2#if NHT > 0
786dff00 3/*
fcc37d29 4 * TM03/TU?? tape driver
786dff00 5 */
786dff00
BJ
6#include "../h/param.h"
7#include "../h/systm.h"
8#include "../h/buf.h"
9#include "../h/conf.h"
10#include "../h/dir.h"
11#include "../h/file.h"
12#include "../h/user.h"
13#include "../h/map.h"
80e7c811 14#include "../h/pte.h"
786dff00 15#include "../h/mba.h"
fcc37d29
BJ
16#include "../h/mtio.h"
17#include "../h/ioctl.h"
f0a3ddbd 18#include "../h/cmap.h"
786dff00 19
fcc37d29
BJ
20#include "../h/htreg.h"
21
22struct buf rhtbuf[NHT];
23struct buf chtbuf[NHT];
24
25short httypes[] =
26 { MBDT_TE16, MBDT_TU45, MBDT_TU77, 0 };
27struct mba_info *htinfo[NHT];
28int htdkinit(), htustart(), htndtint(), htdtint();
29struct mba_driver htdriver =
30 { htdkinit, htustart, 0, htdtint, htndtint, httypes, htinfo };
31
32#define MASKREG(r) ((r) & 0xffff)
33
34/* bits in minor device */
35#define HTUNIT(dev) (minor(dev)&03)
36#define H_NOREWIND 04
37#define H_1600BPI 08
786dff00 38
fcc37d29
BJ
39#define INF (daddr_t)1000000L /* a block number that wont exist */
40
41struct ht_softc {
42 char sc_openf;
43 char sc_flags;
44 daddr_t sc_blkno;
45 daddr_t sc_nxrec;
46 u_short sc_erreg;
47 u_short sc_dsreg;
48 short sc_resid;
49 short sc_dens;
50} ht_softc[NHT];
51
fcc37d29
BJ
52/*
53 * Bits for sc_flags.
54 */
55#define H_WRITTEN 1 /* last operation was a write */
56#define H_ERASED 2 /* last write retry was an erase gap */
57#define H_REWIND 4 /* last unit start was a rewind */
786dff00 58
fcc37d29
BJ
59/*ARGSUSED*/
60htdkinit(mi)
61 struct mba_info *mi;
62{
63
64}
786dff00
BJ
65
66htopen(dev, flag)
fcc37d29
BJ
67 dev_t dev;
68 int flag;
786dff00 69{
fcc37d29
BJ
70 register int unit;
71 register struct mba_info *mi;
72 register struct ht_softc *sc;
786dff00 73
fcc37d29
BJ
74 unit = HTUNIT(dev);
75 if (unit >= NHT || (sc = &ht_softc[unit])->sc_openf ||
76 (mi = htinfo[unit]) == 0 || mi->mi_alive == 0) {
786dff00
BJ
77 u.u_error = ENXIO;
78 return;
79 }
fcc37d29
BJ
80 /*
81 * The NOP below serves two purposes:
82 * 1. To get a recent copy of the status registers.
83 * 2. To ensure that any outstanding rewinds are truly finished
fcc37d29
BJ
84 */
85 htcommand(dev, HT_SENSE, 1);
86 if ((sc->sc_dsreg & HTDS_MOL) == 0 ||
87 (flag & (FREAD|FWRITE)) == FWRITE && sc->sc_dsreg&HTDS_WRL) {
88 u.u_error = EIO;
89 return;
90 }
91 sc->sc_dens =
dc637456
BJ
92 ((minor(dev)&H_1600BPI)?HTTC_1600BPI:HTTC_800BPI)|HTTC_PDP11|mi->mi_slave;
93 printf("dens %o\n", sc->sc_dens);
fcc37d29
BJ
94 sc->sc_openf = 1;
95 sc->sc_blkno = (daddr_t)0;
96 sc->sc_nxrec = INF;
97 sc->sc_flags = 0;
786dff00
BJ
98}
99
100htclose(dev, flag)
fcc37d29
BJ
101 register dev_t dev;
102 register flag;
786dff00 103{
fcc37d29 104 register struct ht_softc *sc = &ht_softc[HTUNIT(dev)];
786dff00 105
fcc37d29
BJ
106 if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN))) {
107 htcommand(dev, HT_WEOF, 1);
108 htcommand(dev, HT_WEOF, 1);
109 htcommand(dev, HT_SREV, 1);
786dff00 110 }
fcc37d29
BJ
111 if ((minor(dev)&H_NOREWIND) == 0)
112 /* 0 as third arg means don't wait */
113 htcommand(dev, HT_REW, 0);
114 sc->sc_openf = 0;
786dff00
BJ
115}
116
fcc37d29
BJ
117/*
118 * Do a non-data-transfer command.
119 *
120 * N.B.: Count should be zero ONLY for rewind during close.
121 */
122htcommand(dev, com, count)
123 dev_t dev;
124 int com, count;
786dff00
BJ
125{
126 register struct buf *bp;
127
fcc37d29 128 bp = &chtbuf[HTUNIT(dev)];
81263dba 129 (void) spl5();
fcc37d29 130 while (bp->b_flags&B_BUSY) {
786dff00
BJ
131 bp->b_flags |= B_WANTED;
132 sleep((caddr_t)bp, PRIBIO);
133 }
dc637456 134 bp->b_flags = B_BUSY|B_READ;
81263dba 135 (void) spl0();
786dff00 136 bp->b_dev = dev;
fcc37d29
BJ
137 bp->b_command = com;
138 bp->b_repcnt = count;
786dff00 139 bp->b_blkno = 0;
786dff00 140 htstrategy(bp);
fcc37d29
BJ
141 if (count == 0)
142 return;
786dff00 143 iowait(bp);
fcc37d29 144 if (bp->b_flags&B_WANTED)
786dff00 145 wakeup((caddr_t)bp);
fcc37d29 146 bp->b_flags &= B_ERROR;
786dff00
BJ
147}
148
149htstrategy(bp)
fcc37d29 150 register struct buf *bp;
786dff00 151{
fcc37d29 152 register int unit = HTUNIT(bp->b_dev);
dc637456 153 register struct mba_info *mi = htinfo[unit];
fcc37d29
BJ
154 register struct buf *dp;
155 register struct ht_softc *sc = &ht_softc[unit];
786dff00 156
786dff00 157 bp->av_forw = NULL;
fcc37d29 158 dp = &mi->mi_tab;
81263dba 159 (void) spl5();
fcc37d29
BJ
160 if (dp->b_actf == NULL)
161 dp->b_actf = bp;
786dff00 162 else
fcc37d29
BJ
163 dp->b_actl->av_forw = bp;
164 dp->b_actl = bp;
165 if (dp->b_active == 0)
166 mbustart(mi);
81263dba 167 (void) spl0();
786dff00
BJ
168}
169
fcc37d29
BJ
170htustart(mi)
171 register struct mba_info *mi;
786dff00 172{
fcc37d29
BJ
173 register struct htdevice *htaddr =
174 (struct htdevice *)mi->mi_drv;
175 register struct buf *bp = mi->mi_tab.b_actf;
176 int unit = HTUNIT(bp->b_dev);
177 register struct ht_softc *sc = &ht_softc[unit];
786dff00
BJ
178 daddr_t blkno;
179
fcc37d29
BJ
180 htaddr->httc = sc->sc_dens;
181 sc->sc_dsreg = htaddr->htds;
182 sc->sc_erreg = htaddr->hter;
183 sc->sc_resid = htaddr->htfc;
184 sc->sc_flags &= ~(H_WRITTEN|H_REWIND);
185 if ((htaddr->htdt & HTDT_SPR) == 0 || (htaddr->htds & HTDS_MOL) == 0)
186 if (sc->sc_openf > 0)
187 sc->sc_openf = -1;
188 if (sc->sc_openf < 0) {
189 bp->b_flags |= B_ERROR;
190 return (MBU_NEXT);
191 }
192 if (bp != &chtbuf[unit]) {
193 if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
194 bp->b_flags |= B_ERROR;
195 bp->b_error = ENXIO;
196 goto next;
197 } else if (dbtofsb(bp->b_blkno) == sc->sc_nxrec &&
198 bp->b_flags&B_READ) {
199 bp->b_resid = bp->b_bcount;
200 clrbuf(bp);
786dff00 201 goto next;
fcc37d29
BJ
202 } else if ((bp->b_flags&B_READ)==0)
203 sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
204 } else {
dc637456
BJ
205 if (bp->b_command == HT_SENSE) {
206 T(10)("sense complete\n");
fcc37d29 207 return (MBU_NEXT);
dc637456 208 }
fcc37d29
BJ
209 if (bp->b_command == HT_REW)
210 sc->sc_flags |= H_REWIND;
211 else
212 htaddr->htfc = -bp->b_bcount;
213 htaddr->htcs1 = bp->b_command|HT_GO;
dc637456 214 T(10)("started cmd %d\n", bp->b_command);
fcc37d29
BJ
215 return (MBU_STARTED);
216 }
217 if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
218 htaddr->htfc = -bp->b_bcount;
219 if ((bp->b_flags&B_READ) == 0) {
220 if (mi->mi_tab.b_errcnt)
221 if (sc->sc_flags & H_ERASED)
222 sc->sc_flags &= ~H_ERASED;
223 else {
224 sc->sc_flags |= H_ERASED;
225 htaddr->htcs1 = HT_ERASE | HT_GO;
226 return (MBU_STARTED);
227 }
228 if (htaddr->htds & HTDS_EOT) {
229 bp->b_resid = bp->b_bcount;
230 return (MBU_NEXT);
231 }
786dff00 232 }
fcc37d29 233 return (MBU_DODATA);
786dff00 234 }
fcc37d29
BJ
235 if (blkno < dbtofsb(bp->b_blkno)) {
236 htaddr->htfc = blkno - dbtofsb(bp->b_blkno);
dc637456 237 T(10)("spacing fwd %d\n", MASKREG(htaddr)->htfc);
fcc37d29 238 htaddr->htcs1 = HT_SFORW|HT_GO;
786dff00 239 } else {
fcc37d29 240 htaddr->htfc = dbtofsb(bp->b_blkno) - blkno;
dc637456 241 T(10)("spacing back %d\n", MASKREG(htaddr)->htfc);
fcc37d29 242 htaddr->htcs1 = HT_SREV|HT_GO;
786dff00 243 }
fcc37d29
BJ
244 return (MBU_STARTED);
245next:
786dff00 246 iodone(bp);
fcc37d29 247 return (MBU_NEXT);
786dff00
BJ
248}
249
fcc37d29
BJ
250/*
251 * data transfer interrupt - must be read or write
252 */
786dff00 253/*ARGSUSED*/
fcc37d29
BJ
254htdtint(mi, mbasr)
255 register struct mba_info *mi;
256 int mbasr;
786dff00 257{
fcc37d29
BJ
258 register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
259 register struct buf *bp = mi->mi_tab.b_actf;
260 register struct ht_softc *sc;
261 int ds, er;
786dff00 262
fcc37d29
BJ
263 sc = &ht_softc[HTUNIT(bp->b_dev)];
264 ds = sc->sc_dsreg = MASKREG(htaddr->htds);
265 er = sc->sc_erreg = MASKREG(htaddr->hter);
266 sc->sc_resid = MASKREG(htaddr->htfc);
267 sc->sc_blkno++;
268 if((bp->b_flags & B_READ) == 0)
269 sc->sc_flags |= H_WRITTEN;
270 if ((ds&(HTDS_ERR|HTDS_MOL)) != HTDS_MOL ||
271 mbasr & MBAEBITS) {
272 htaddr->htcs1 = HT_DCLR|HT_GO;
273 if (bp == &rhtbuf[HTUNIT(bp->b_dev)])
274 er &= ~HTER_FCE;
275 if (bp->b_flags & B_READ && ds & HTDS_PES)
276 er &= ~(HTER_CSITM|HTER_CORCRC);
277 if (er&HTER_HARD ||
278 mbasr&MBAEBITS || (ds&HTDS_MOL) == 0 ||
279 sc->sc_erreg && ++mi->mi_tab.b_errcnt >= 7) {
280 if ((ds & HTDS_MOL) == 0 && sc->sc_openf > 0)
281 sc->sc_openf = -1;
282 printf("ht%d: hard error bn%d mbasr=%b er=%b\n",
283 HTUNIT(bp->b_dev), bp->b_blkno,
284 mbasr, mbasr_bits,
285 MASKREG(htaddr->hter), HTER_BITS);
786dff00 286 bp->b_flags |= B_ERROR;
fcc37d29 287 return (MBD_DONE);
786dff00 288 }
fcc37d29
BJ
289 if (er)
290 return (MBD_RETRY);
786dff00 291 }
fcc37d29
BJ
292 bp->b_resid = 0;
293 if (bp->b_flags & B_READ)
294 if (ds&HTDS_TM) { /* must be a read, right? */
295 bp->b_resid = bp->b_bcount;
296 sc->sc_nxrec = dbtofsb(bp->b_blkno);
297 } else if(bp->b_bcount > MASKREG(htaddr->htfc))
298 bp->b_resid = bp->b_bcount - MASKREG(htaddr->htfc);
299 return (MBD_DONE);
300}
786dff00 301
fcc37d29
BJ
302/*
303 * non-data-transfer interrupt
304 */
305htndtint(mi)
306 register struct mba_info *mi;
307{
308 register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
309 register struct buf *bp = mi->mi_tab.b_actf;
310 register struct ht_softc *sc;
311 int er, ds, fc;
786dff00 312
fcc37d29
BJ
313 sc = &ht_softc[HTUNIT(bp->b_dev)];
314 ds = sc->sc_dsreg = MASKREG(htaddr->htds);
315 er = sc->sc_erreg = MASKREG(htaddr->hter);
316 sc->sc_resid = MASKREG(htaddr->htfc);
317 if (sc->sc_erreg)
318 htaddr->htcs1 = HT_DCLR|HT_GO;
319 if (bp == &chtbuf[HTUNIT(bp->b_dev)]) {
320 if (bp->b_command == HT_REWOFFL)
321 /* offline is on purpose; don't do anything special */
322 ds |= HTDS_MOL;
323 else if (bp->b_resid == HT_SREV &&
324 er == (HTER_NEF|HTER_FCE) &&
325 ds&HTDS_BOT && bp->b_bcount == INF)
326 er &= ~HTER_NEF;
327 er &= ~HTER_FCE;
328 if (er == 0)
329 ds &= ~HTDS_ERR;
330 }
331 if ((ds & (HTDS_ERR|HTDS_MOL)) != HTDS_MOL) {
332 if ((ds & HTDS_MOL) == 0 && sc->sc_openf > 0)
333 sc->sc_openf = -1;
334 printf("ht%d: hard error bn%d er=%b ds=%b\n",
335 HTUNIT(bp->b_dev), bp->b_blkno,
336 sc->sc_erreg, HTER_BITS, sc->sc_dsreg, HTDS_BITS);
337 bp->b_flags |= B_ERROR;
338 return (MBN_DONE);
786dff00 339 }
fcc37d29
BJ
340 if (bp == &chtbuf[HTUNIT(bp->b_dev)]) {
341 if (sc->sc_flags & H_REWIND)
342 return (ds & HTDS_BOT ? MBN_DONE : MBN_RETRY);
343 bp->b_resid = -sc->sc_resid;
344 return (MBN_DONE);
345 }
346 if (ds & HTDS_TM)
347 if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {/* reversing */
348 sc->sc_nxrec = dbtofsb(bp->b_blkno) - fc;
349 sc->sc_blkno = sc->sc_nxrec;
350 } else { /* spacing forward */
351 sc->sc_blkno = dbtofsb(bp->b_blkno) + fc;
352 sc->sc_nxrec = sc->sc_blkno - 1;
353 }
354 else
355 sc->sc_blkno = dbtofsb(bp->b_blkno);
356 return (MBN_RETRY);
786dff00
BJ
357}
358
359htread(dev)
fcc37d29 360 dev_t dev;
786dff00 361{
fcc37d29 362
786dff00 363 htphys(dev);
fcc37d29
BJ
364 if (u.u_error)
365 return;
366 physio(htstrategy, &rhtbuf[HTUNIT(dev)], dev, B_READ, minphys);
786dff00
BJ
367}
368
369htwrite(dev)
370{
fcc37d29 371
786dff00 372 htphys(dev);
fcc37d29
BJ
373 if (u.u_error)
374 return;
375 physio(htstrategy, &rhtbuf[HTUNIT(dev)], dev, B_WRITE, minphys);
786dff00
BJ
376}
377
378htphys(dev)
fcc37d29 379 dev_t dev;
786dff00 380{
fcc37d29
BJ
381 register int unit;
382 register struct ht_softc *sc;
786dff00
BJ
383 daddr_t a;
384
fcc37d29
BJ
385 unit = HTUNIT(dev);
386 if (unit >= NHT) {
387 u.u_error = ENXIO;
388 return;
786dff00 389 }
fcc37d29
BJ
390 a = u.u_offset >> 9;
391 sc = &ht_softc[unit];
392 sc->sc_blkno = dbtofsb(a);
393 sc->sc_nxrec = dbtofsb(a)+1;
786dff00 394}
f0a3ddbd 395
fcc37d29
BJ
396/*ARGSUSED*/
397htioctl(dev, cmd, addr, flag)
398 dev_t dev;
399 int cmd;
400 caddr_t addr;
401 int flag;
402{
403 register unit = HTUNIT(dev);
404 register struct ht_softc *sc = &ht_softc[unit];
405 register struct buf *bp = &chtbuf[unit];
406 register callcount;
407 int fcount;
408 struct mtop mtop;
409 struct mtget mtget;
410 /* we depend of the values and order of the MT codes here */
411 static htops[] =
412 {HT_WEOF,HT_SFORW,HT_SREV,HT_SFORW,HT_SREV,HT_REW,HT_REWOFFL,HT_SENSE};
413
414 switch (cmd) {
415 case MTIOCTOP: /* tape operation */
416 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
417 u.u_error = EFAULT;
418 return;
419 }
420 switch(mtop.mt_op) {
421 case MTWEOF:
422 callcount = mtop.mt_count;
423 fcount = 1;
424 break;
425 case MTFSF: case MTBSF:
426 callcount = mtop.mt_count;
427 fcount = INF;
428 break;
429 case MTFSR: case MTBSR:
430 callcount = 1;
431 fcount = mtop.mt_count;
432 break;
433 case MTREW: case MTOFFL:
434 callcount = 1;
435 fcount = 1;
436 break;
437 default:
438 u.u_error = ENXIO;
439 return;
440 }
441 if (callcount <= 0 || fcount <= 0) {
442 u.u_error = ENXIO;
443 return;
444 }
445 while (--callcount >= 0) {
446 htcommand(dev, htops[mtop.mt_op], fcount);
447 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
448 bp->b_resid) {
449 u.u_error = EIO;
450 break;
451 }
452 if ((chtbuf[HTUNIT(bp->b_dev)].b_flags&B_ERROR) ||
453 sc->sc_dsreg&HTDS_BOT)
454 break;
455 }
456 geterror(bp);
457 return;
458 case MTIOCGET:
459 mtget.mt_dsreg = sc->sc_dsreg;
460 mtget.mt_erreg = sc->sc_erreg;
461 mtget.mt_resid = sc->sc_resid;
462 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
463 u.u_error = EFAULT;
464 return;
465 default:
466 u.u_error = ENXIO;
467 }
468}
f0a3ddbd
BJ
469
470#define DBSIZE 20
471
fcc37d29 472htdump()
f0a3ddbd 473{
fcc37d29
BJ
474 register struct mba_info *mi;
475 register struct mba_regs *mp;
476 register struct htdevice *htaddr;
477 int blk, num;
478 int start;
479
480 start = 0;
481 num = maxfree;
482#define phys(a,b) ((b)((int)(a)&0x7fffffff))
483 if (htinfo[0] == 0)
484 return (ENXIO);
485 mi = phys(htinfo[0], struct mba_info *);
486 mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
487#if VAX780
488 mbainit(mp);
489 htaddr = (struct htdevice *)&mp->mba_drv[mi->mi_drive];
490 htaddr->httc = HTTC_PDP11|HTTC_1600BPI;
491 htaddr->htcs1 = HT_DCLR|HT_GO;
f0a3ddbd
BJ
492 while (num > 0) {
493 blk = num > DBSIZE ? DBSIZE : num;
fcc37d29
BJ
494 htdwrite(start, blk, htaddr, mp);
495 start += blk;
f0a3ddbd
BJ
496 num -= blk;
497 }
fcc37d29
BJ
498 htwait(htaddr);
499 htaddr->htcs1 = HT_REW|HT_GO;
500 hteof(htaddr);
501 hteof(htaddr);
f0a3ddbd
BJ
502}
503
fcc37d29
BJ
504htdwrite(dbuf, num, htaddr, mp)
505 register dbuf, num;
506 register struct htdevice *htaddr;
507 struct mba_regs *mp;
f0a3ddbd 508{
fcc37d29 509 register struct pte *io;
f0a3ddbd
BJ
510 register int i;
511
fcc37d29
BJ
512 htwait(htaddr);
513 io = mp->mba_map;
f0a3ddbd 514 for (i = 0; i < num; i++)
fcc37d29
BJ
515 *(int *)io++ = dbuf++ | PG_V;
516 htaddr->htfc = -(num*NBPG);
517 mp->mba_sr = -1;
518 mp->mba_bcr = -(num*NBPG);
519 mp->mba_var = 0;
520 htaddr->htcs1 = HT_WCOM|HT_GO;
f0a3ddbd
BJ
521}
522
fcc37d29
BJ
523htwait(htaddr)
524 struct htdevice *htaddr;
f0a3ddbd
BJ
525{
526 register s;
527
528 do
fcc37d29
BJ
529 s = htaddr->htds;
530 while ((s & HTDS_DRY) == 0);
f0a3ddbd
BJ
531}
532
fcc37d29
BJ
533hteof(htaddr)
534 struct htdevice *htaddr;
f0a3ddbd
BJ
535{
536
fcc37d29
BJ
537 htwait(htaddr);
538 htaddr->htcs1 = HT_WEOF|HT_GO;
f0a3ddbd 539}
a5cc519e 540#endif