use shorts to move data
[unix-history] / usr / src / sys / vax / mba / mt.c
CommitLineData
155d9ff0 1/* mt.c 4.3 82/03/14 */
83d7e407
BJ
2
3#include "mu.h"
4#if NMT > 0
5/*
6 * TM78/TU78 tape driver
7 *
8 * Behavior in complex error situations is uncertain...
9 *
10 * TODO:
11 * test error recovery
12 * add odd byte count kludge from VMS driver
13 * write dump routine
14 */
15#include "../h/param.h"
16#include "../h/systm.h"
17#include "../h/buf.h"
18#include "../h/conf.h"
19#include "../h/dir.h"
20#include "../h/file.h"
21#include "../h/user.h"
22#include "../h/map.h"
23#include "../h/pte.h"
24#include "../h/mbareg.h"
25#include "../h/mbavar.h"
26#include "../h/mtio.h"
27#include "../h/ioctl.h"
28#include "../h/cmap.h"
29#include "../h/cpu.h"
30
31#include "../h/mtreg.h"
32
33struct buf rmtbuf[NMT];
34struct buf cmtbuf[NMT];
35
36short mttypes[] =
37 { MBDT_TU78, 0 };
38struct mba_device *mtinfo[NMT];
39int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
40struct mba_driver mtdriver =
41 { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
42 mttypes, "mt", "mu", mtinfo };
43
44#define MASKREG(r) ((r) & 0xffff)
45
46/* bits in minor device */
47#define MUUNIT(dev) (minor(dev)&03)
48#define H_NOREWIND 04
49#define H_6250BPI 08
50
51#define MTUNIT(dev) (mutomt[MUUNIT(dev)])
52
53#define INF (daddr_t)1000000L /* a block number that wont exist */
54
55struct mu_softc {
56 char sc_openf;
57 char sc_flags;
58 daddr_t sc_blkno;
59 daddr_t sc_nxrec;
60 u_short sc_erreg;
61 u_short sc_dsreg;
62 short sc_resid;
63 short sc_dens;
64 struct mba_device *sc_mi;
65 int sc_slave;
66} mu_softc[NMU];
67short mutomt[NMU];
68
69/*
70 * Bits for sc_flags.
71 */
72#define H_WRITTEN 1 /* last operation was a write */
73
74char mtds_bits[] = MTDS_BITS;
75
76/*ARGSUSED*/
77mtattach(mi)
78 struct mba_device *mi;
79{
155d9ff0
SL
80#ifdef lint
81 mtread(0); mtwrite(0); mtioctl(0, 0, 0, 0);
82#endif
83d7e407
BJ
83}
84
85mtslave(mi, ms)
86 struct mba_device *mi;
87 struct mba_slave *ms;
88{
89 register struct mu_softc *sc = &mu_softc[ms->ms_unit];
90 register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
91 int s = spl7(), rtn = 0;
92
93 mtaddr->mtas = -1;
94 mtaddr->mtncs[ms->ms_slave] = MT_SENSE|MT_GO;
95 while (mtaddr->mtas == 0)
96 ;
97 if ((mtaddr->mtner & MTER_INTCODE) == MTER_DONE &&
98 (mtaddr->mtds & MTDS_PRES)) {
99 sc->sc_mi = mi;
100 sc->sc_slave = ms->ms_slave;
101 mutomt[ms->ms_unit] = mi->mi_unit;
102 rtn = 1;
103 }
104 mtaddr->mtas = mtaddr->mtas;
105 splx(s);
106 return (rtn);
107}
108
109mtopen(dev, flag)
110 dev_t dev;
111 int flag;
112{
113 register int muunit;
114 register struct mba_device *mi;
115 register struct mu_softc *sc;
116 int olddens, dens;
117
118 muunit = MUUNIT(dev);
119 if (muunit >= NMU || (sc = &mu_softc[muunit])->sc_openf ||
120 (mi = mtinfo[MTUNIT(dev)]) == 0 || mi->mi_alive == 0) {
121 u.u_error = ENXIO;
122 return;
123 }
124 olddens = sc->sc_dens;
125 dens = sc->sc_dens = (minor(dev)&H_6250BPI) ? MT_GCR : 0;
126 mtcommand(dev, MT_SENSE, 1);
127 sc->sc_dens = olddens;
128 if ((sc->sc_dsreg & MTDS_ONL) == 0) {
129 uprintf("mu%d: not online\n", muunit);
130 u.u_error = EIO;
131 return;
132 }
133 if ((flag&FWRITE) && (sc->sc_dsreg&MTDS_FPT)) {
134 uprintf("mu%d: no write ring\n", muunit);
135 u.u_error = EIO;
136 return;
137 }
138 if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag&FWRITE) &&
139 dens != sc->sc_dens) {
140 uprintf("mu%d: can't change density in mid-tape\n", muunit);
141 u.u_error = EIO;
142 return;
143 }
144 sc->sc_openf = 1;
145 sc->sc_blkno = (daddr_t)0;
146 sc->sc_nxrec = INF;
147 sc->sc_flags = 0;
148 sc->sc_dens = dens;
149}
150
151mtclose(dev, flag)
152 register dev_t dev;
153 register flag;
154{
155 register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
156
157 if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN)))
158 mtcommand(dev, MT_CLS|sc->sc_dens, 1);
159 if ((minor(dev)&H_NOREWIND) == 0)
160 mtcommand(dev, MT_REW, 0);
161 sc->sc_openf = 0;
162}
163
164mtcommand(dev, com, count)
165 dev_t dev;
166 int com, count;
167{
168 register struct buf *bp;
2311123d 169 register int s;
83d7e407
BJ
170
171 bp = &cmtbuf[MTUNIT(dev)];
2311123d 172 s = spl5();
83d7e407
BJ
173 while (bp->b_flags&B_BUSY) {
174 if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
175 break;
176 bp->b_flags |= B_WANTED;
177 sleep((caddr_t)bp, PRIBIO);
178 }
179 bp->b_flags = B_BUSY|B_READ;
2311123d 180 splx(s);
83d7e407
BJ
181 bp->b_dev = dev;
182 bp->b_command = com;
183 bp->b_repcnt = count;
184 bp->b_blkno = 0;
185 mtstrategy(bp);
186 if (count == 0)
187 return;
188 iowait(bp);
189 if (bp->b_flags&B_WANTED)
190 wakeup((caddr_t)bp);
191 bp->b_flags &= B_ERROR;
192}
193
194mtstrategy(bp)
195 register struct buf *bp;
196{
197 register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
198 register struct buf *dp;
2311123d 199 register int s;
83d7e407
BJ
200
201 bp->av_forw = NULL;
202 dp = &mi->mi_tab;
2311123d 203 s = spl5();
83d7e407
BJ
204 if (dp->b_actf == NULL)
205 dp->b_actf = bp;
206 else
207 dp->b_actl->av_forw = bp;
208 dp->b_actl = bp;
209 if (dp->b_active == 0)
210 mbustart(mi);
2311123d 211 splx(s);
83d7e407
BJ
212}
213
214mtustart(mi)
215 register struct mba_device *mi;
216{
217 register struct mtdevice *mtaddr =
218 (struct mtdevice *)mi->mi_drv;
219 register struct buf *bp = mi->mi_tab.b_actf;
220 register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
221 daddr_t blkno;
222
223 sc->sc_flags &= ~H_WRITTEN;
224 if (sc->sc_openf < 0) {
225 bp->b_flags |= B_ERROR;
226 return (MBU_NEXT);
227 }
228 if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
229 if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
230 bp->b_flags |= B_ERROR;
231 bp->b_error = ENXIO;
232 return (MBU_NEXT);
233 }
234 if (dbtofsb(bp->b_blkno) == sc->sc_nxrec &&
235 bp->b_flags&B_READ) {
236 bp->b_resid = bp->b_bcount;
237 clrbuf(bp);
238 return (MBU_NEXT);
239 }
240 if ((bp->b_flags&B_READ)==0)
241 sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
242 } else {
243 mtaddr->mtncs[MUUNIT(bp->b_dev)] =
244 (bp->b_repcnt<<8)|bp->b_command|MT_GO;
245 return (MBU_STARTED);
246 }
247 if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
248 if (mi->mi_tab.b_errcnt == 2) {
249 mtaddr->mtca = MUUNIT(bp->b_dev);
250 } else {
251 mtaddr->mtbc = bp->b_bcount;
252 mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
253 }
254 return (MBU_DODATA);
255 }
256 if (blkno < dbtofsb(bp->b_blkno))
257 mtaddr->mtncs[MUUNIT(bp->b_dev)] =
155d9ff0
SL
258 (min((unsigned)(dbtofsb(bp->b_blkno) - blkno), 0377) << 8) |
259 MT_SFORW|MT_GO;
83d7e407
BJ
260 else
261 mtaddr->mtncs[MUUNIT(bp->b_dev)] =
155d9ff0
SL
262 (min((unsigned)(blkno - dbtofsb(bp->b_blkno)), 0377) << 8) |
263 MT_SREV|MT_GO;
83d7e407
BJ
264 return (MBU_STARTED);
265}
266
267mtstart(mi)
268 register struct mba_device *mi;
269{
270 register struct buf *bp = mi->mi_tab.b_actf;
271 register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
272
273 if (bp->b_flags & B_READ)
274 if (mi->mi_tab.b_errcnt == 2)
275 return(MT_READREV|MT_GO);
276 else
277 return(MT_READ|MT_GO);
278 else
279 return(MT_WRITE|sc->sc_dens|MT_GO);
280}
281
282mtdtint(mi, mbsr)
283 register struct mba_device *mi;
284 int mbsr;
285{
286 register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
287 register struct buf *bp = mi->mi_tab.b_actf;
288 register struct mu_softc *sc;
289
290 /* I'M NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
291 if ((mtaddr->mtca&3) != MUUNIT(bp->b_dev)) {
292 printf("mt: wrong unit!\n");
293 mtaddr->mtca = MUUNIT(bp->b_dev);
294 }
295 sc = &mu_softc[MUUNIT(bp->b_dev)];
296 sc->sc_erreg = mtaddr->mter;
297 if((bp->b_flags & B_READ) == 0)
298 sc->sc_flags |= H_WRITTEN;
299 switch (sc->sc_erreg & MTER_INTCODE) {
300 case MTER_DONE:
301 case MTER_LONGREC:
302 if (mi->mi_tab.b_errcnt != 2)
303 sc->sc_blkno++;
304 bp->b_resid = 0;
305 break;
306
307 case MTER_NOTCAP:
308 printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
309 goto err;
310
311 case MTER_TM:
312 case MTER_EOT:
313 sc->sc_blkno++;
314 err:
315 bp->b_resid = bp->b_bcount;
316 sc->sc_nxrec = dbtofsb(bp->b_blkno);
317 break;
318
319 case MTER_SHRTREC:
320 sc->sc_blkno++;
321 if (bp != &rmtbuf[MTUNIT(bp->b_dev)])
322 bp->b_flags |= B_ERROR;
323 if (mi->mi_tab.b_errcnt == 2)
324 bp->b_bcount = bp->b_resid; /* restore saved value */
325 bp->b_resid = bp->b_bcount - mtaddr->mtbc;
326 break;
327
328 case MTER_RDOPP:
329 mi->mi_tab.b_errcnt = 2; /* indicate "read opposite" */
330 bp->b_resid = bp->b_bcount; /* save it */
331 bp->b_bcount = mtaddr->mtbc; /* use this instead */
332 return(MBD_RETRY);
333
334 case MTER_RETRY:
335 mi->mi_tab.b_errcnt = 1; /* indicate simple retry */
336 return(MBD_RETRY);
337
338 case MTER_OFFLINE:
339 if (sc->sc_openf > 0) {
340 sc->sc_openf = -1;
341 printf("mu%d: offline\n", MUUNIT(bp->b_dev));
342 }
343 bp->b_flags |= B_ERROR;
344 break;
345
346 case MTER_FPT:
347 printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
348 bp->b_flags |= B_ERROR;
349 break;
350
351 default:
352 printf("mu%d: hard error bn%d mbsr=%b er=%x ds=%b\n",
353 MUUNIT(bp->b_dev), bp->b_blkno,
354 mbsr, mbsr_bits, sc->sc_erreg,
355 sc->sc_dsreg, mtds_bits);
356 bp->b_flags |= B_ERROR;
357 mtaddr->mtid = MTID_CLR; /* reset the TM78 */
358 DELAY(250);
359 while ((mtaddr->mtid & MTID_RDY) == 0) /* wait for it */
360 ;
361 return (MBD_DONE);
362 }
363 /* CHECK FOR MBA ERROR WHEN NO OTHER ERROR INDICATED? */
364 return (MBD_DONE);
365}
366
367mtndtint(mi)
368 register struct mba_device *mi;
369{
370 register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
371 register struct buf *bp = mi->mi_tab.b_actf;
372 register struct mu_softc *sc;
373 int er, fc, unit;
374
375 unit = (mtaddr->mtner >> 8) & 3;
376 er = MASKREG(mtaddr->mtner);
377 /* WILL THIS OCCUR IF ANOTHER DRIVE COMES ONLINE? */
378 if (bp == 0 || unit != MUUNIT(bp->b_dev)) { /* consistency check */
379 if ((er & MTER_INTCODE) != MTER_ONLINE)
380 printf("mt: unit %d random interrupt\n", unit);
381 return (MBN_SKIP);
382 }
383 if (bp == 0)
384 return (MBN_SKIP);
385 fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
386 sc = &mu_softc[unit];
387 sc->sc_erreg = er;
388 sc->sc_resid = fc;
389 switch (er & MTER_INTCODE) {
390 case MTER_DONE:
391 if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
392 done:
393 if (bp->b_command == MT_SENSE)
394 sc->sc_dsreg = MASKREG(mtaddr->mtds);
395 bp->b_resid = fc;
396 return (MBN_DONE);
397 }
398 /* this is UGLY! (but is it correct?) */
399 if ((fc = dbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
155d9ff0 400 sc->sc_blkno -= MIN(0377, -fc);
83d7e407 401 else
155d9ff0 402 sc->sc_blkno += MIN(0377, fc);
83d7e407
BJ
403 return (MBN_RETRY);
404
405 case MTER_RWDING:
406 return (MBN_SKIP); /* ignore "rewind started" interrupt */
407
408 case MTER_NOTCAP:
409 printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
410
411 case MTER_TM:
412 case MTER_EOT:
413 case MTER_LEOT:
414 if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
415 sc->sc_nxrec = dbtofsb(bp->b_blkno) + fc;
416 sc->sc_blkno = sc->sc_nxrec;
417 } else {
418 sc->sc_blkno = dbtofsb(bp->b_blkno) - fc;
419 sc->sc_nxrec = sc->sc_blkno - 1;
420 }
421 return (MBN_RETRY);
422
423 case MTER_FPT:
424 printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
425 bp->b_flags |= B_ERROR;
426 return (MBN_DONE);
427
428 case MTER_OFFLINE:
429 if (sc->sc_openf > 0) {
430 sc->sc_openf = -1;
431 printf("mu%d: offline\n", MUUNIT(bp->b_dev));
432 }
433 bp->b_flags |= B_ERROR;
434 return (MBN_DONE);
435
436 case MTER_BOT:
437 if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
438 goto done;
439 /* FALL THROUGH */
440
441 default:
442 printf("mu%d: hard error bn%d er=%o ds=%b\n",
443 MUUNIT(bp->b_dev), bp->b_blkno,
444 sc->sc_erreg, sc->sc_dsreg, mtds_bits);
445 mtaddr->mtid = MTID_CLR; /* reset the TM78 */
446 DELAY(250);
447 while ((mtaddr->mtid & MTID_RDY) == 0) /* wait for it */
448 ;
449 bp->b_flags |= B_ERROR;
450 return (MBN_DONE);
451 }
452 /* NOTREACHED */
453}
454
455mtread(dev)
456 dev_t dev;
457{
458
459 mtphys(dev);
460 if (u.u_error)
461 return;
462 physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys);
463}
464
465mtwrite(dev)
466{
467
468 mtphys(dev);
469 if (u.u_error)
470 return;
471 physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys);
472}
473
474mtphys(dev)
475 dev_t dev;
476{
477 register int mtunit;
478 register struct mu_softc *sc;
479 register struct mba_device *mi;
480 daddr_t a;
481
482 mtunit = MTUNIT(dev);
483 if (mtunit >= NMT || (mi = mtinfo[mtunit]) == 0 || mi->mi_alive == 0) {
484 u.u_error = ENXIO;
485 return;
486 }
487 a = u.u_offset >> 9;
488 sc = &mu_softc[MUUNIT(dev)];
489 sc->sc_blkno = dbtofsb(a);
490 sc->sc_nxrec = dbtofsb(a)+1;
491}
492
493/*ARGSUSED*/
494mtioctl(dev, cmd, addr, flag)
495 dev_t dev;
496 int cmd;
497 caddr_t addr;
498 int flag;
499{
500 register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
501 register struct buf *bp = &cmtbuf[MTUNIT(dev)];
502 register callcount;
155d9ff0 503 register int op;
83d7e407
BJ
504 int fcount;
505 struct mtop mtop;
506 struct mtget mtget;
507 /* we depend of the values and order of the MT codes here */
508 static mtops[] =
509 {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
510
511 switch (cmd) {
512 case MTIOCTOP: /* tape operation */
513 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
514 u.u_error = EFAULT;
515 return;
516 }
517 switch(mtop.mt_op) {
518 case MTWEOF:
519 callcount = mtop.mt_count;
520 fcount = 1;
521 break;
522 case MTFSF: case MTBSF:
523 callcount = mtop.mt_count;
524 fcount = 1;
525 break;
526 case MTFSR: case MTBSR:
527 callcount = 1;
528 fcount = mtop.mt_count;
529 break;
530 case MTREW: case MTOFFL:
531 callcount = 1;
532 fcount = 1;
533 break;
534 default:
535 u.u_error = ENXIO;
536 return;
537 }
538 if (callcount <= 0 || fcount <= 0) {
539 u.u_error = ENXIO;
540 return;
541 }
542 op = mtops[mtop.mt_op];
543 if (op == MT_WTM)
544 op |= sc->sc_dens;
545 while (--callcount >= 0) {
546 register int n;
547
548 do {
155d9ff0 549 n = MIN(fcount, 0xff);
83d7e407
BJ
550 mtcommand(dev, op, n);
551 fcount -= n;
552 } while (fcount);
553 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
554 bp->b_resid) {
555 u.u_error = EIO;
556 break;
557 }
558 if (bp->b_flags&B_ERROR)
559 break;
560 }
561 geterror(bp);
562 return;
563 case MTIOCGET:
564 mtget.mt_erreg = sc->sc_erreg;
565 mtget.mt_resid = sc->sc_resid;
566 mtcommand(dev, MT_SENSE, 1); /* update drive status */
567 mtget.mt_dsreg = sc->sc_dsreg;
568 mtget.mt_type = MT_ISMT;
569 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
570 u.u_error = EFAULT;
571 return;
572 default:
573 u.u_error = ENXIO;
574 }
575}
576
577#define DBSIZE 20
578
579mtdump()
580{
581 register struct mba_device *mi;
582 register struct mba_regs *mp;
583 register struct mtdevice *mtaddr;
584 int blk, num;
585 int start;
586
587 start = 0;
588 num = maxfree;
589#define phys(a,b) ((b)((int)(a)&0x7fffffff))
590 if (mtinfo[0] == 0)
591 return (ENXIO);
592 mi = phys(mtinfo[0], struct mba_device *);
593 mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
594 mp->mba_cr = MBCR_IE;
155d9ff0
SL
595#if lint
596 blk = blk; num = num; start = start;
597 return (0);
598#endif
83d7e407 599#ifdef notyet
155d9ff0 600 mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
83d7e407
BJ
601 mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
602 mtaddr->mtcs1 = MT_DCLR|MT_GO;
603 while (num > 0) {
604 blk = num > DBSIZE ? DBSIZE : num;
605 mtdwrite(start, blk, mtaddr, mp);
606 start += blk;
607 num -= blk;
608 }
609 mteof(mtaddr);
610 mteof(mtaddr);
611 mtwait(mtaddr);
612 if (mtaddr->mtds&MTDS_ERR)
613 return (EIO);
614 mtaddr->mtcs1 = MT_REW|MT_GO;
615 return (0);
616}
617
618mtdwrite(dbuf, num, mtaddr, mp)
619 register dbuf, num;
620 register struct mtdevice *mtaddr;
621 struct mba_regs *mp;
622{
623 register struct pte *io;
624 register int i;
625
626 mtwait(mtaddr);
627 io = mp->mba_map;
628 for (i = 0; i < num; i++)
629 *(int *)io++ = dbuf++ | PG_V;
630 mtaddr->mtfc = -(num*NBPG);
631 mp->mba_sr = -1;
632 mp->mba_bcr = -(num*NBPG);
633 mp->mba_var = 0;
634 mtaddr->mtcs1 = MT_WCOM|MT_GO;
635}
636
637mtwait(mtaddr)
638 struct mtdevice *mtaddr;
639{
640 register s;
641
642 do
643 s = mtaddr->mtds;
644 while ((s & MTDS_DRY) == 0);
645}
646
647mteof(mtaddr)
648 struct mtdevice *mtaddr;
649{
650
651 mtwait(mtaddr);
652 mtaddr->mtcs1 = MT_WEOF|MT_GO;
653#endif notyet
654}
655#endif