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