|
|
1.1 root 1: /*
2: * DSA tape class driver
3: * drives TMSCP tapes
4: */
5:
6: #include "sys/param.h"
7: #include "sys/buf.h"
8: #include "sys/ta.h"
9: #include "sys/mscp.h"
10: #include "sys/user.h"
11: #include "sys/file.h"
12: #include "sys/conf.h"
13: #include "sys/mtio.h"
14:
15: extern struct msaddr taaddr[];
16: extern struct tatape tatape[];
17: extern int tacnt;
18: static long tarefno; /* ref seq num */
19: extern struct buf tabuf[];
20:
21: static tacmd(), taonline(), tasonl(), tacinit();
22:
23: int taopen(), taread(), tawrite(), taioctl(), tastrategy(), taclose();
24: struct bdevsw tabdev = bdinit(taopen, taclose, tastrategy, B_TAPE);
25: struct cdevsw tacdev = cdinit(taopen, taclose, taread, tawrite, taioctl);
26:
27: /*
28: * minor device number split
29: *
30: * NOCACHE disables write-behind caching; probably useless
31: * DENS selects one of the eight TMSCP density values;
32: * the drive is instructed to use 1<<DENS(dev) in whatever
33: * density language it believes
34: * here are some languages:
35: * for 9-track tapes, (0) 800 bpi (1) PE (2) GCR
36: * for old cartridge tapes (TK50), (3) block tape
37: * for new cartridge tapes (TK70), (0) low density (1) high density
38: * for other TMSCP devices, (0) is usually the right number
39: */
40: #define UNIT(d) ((d)&07)
41: #define DENS(d) (((d)&070)>>3)
42: #define NOCACHE(d) ((d)&0100)
43: #define NOREW(d) ((d)&0200)
44:
45: /*
46: * reused bits of buf/iobuf struct
47: */
48:
49: #define b_next av_forw /* next buffer in queue */
50: #define b_pkt av_back /* pointer to mscp command */
51: #define b_crf b_resid /* saved refno for pending command */
52:
53: /*
54: * flags in tatape.flags
55: */
56:
57: #define ONLINE 01 /* drive is online */
58: #define WONLINE 02 /* waiting for online */
59: #define OPEN 04 /* someone has drive open */
60: #define WRITTEN 010 /* some data was written */
61: #define WPROT 020 /* drive is write protected */
62: #define NEEDCMD 040 /* waiting for some command to start */
63: #define CMDDONE 0100 /* command is finished */
64: #define CMDERR 0200 /* command finished, and error */
65: #define UNHAPPY 0400 /* needs `cache data loss' clear */
66: #define WONLY 01000 /* tape was opened only for writing */
67:
68: /*
69: * random numbers
70: */
71:
72: #define PRIONL (PZERO-1)
73: #define IDTA 1 /* connection ID for MSCP */
74:
75: /*
76: * open a drive
77: */
78:
79: int taseql(), tadg();
80:
81: taopen(dev, flag)
82: dev_t dev;
83: {
84: register int unit;
85: register struct tatape *ta;
86: register struct msaddr *rp;
87: int wasoff;
88:
89: unit = UNIT(dev);
90: if (unit > tacnt) {
91: u.u_error = ENXIO;
92: return;
93: }
94: ta = &tatape[unit];
95: rp = &taaddr[unit];
96: if (ta->flags & OPEN) {
97: u.u_error = EBUSY;
98: return;
99: }
100: if (rp->ctype < 0 || rp->ctype >= nmsport
101: || (ta->port = msportsw[rp->ctype]) == NULL) {
102: u.u_error = ENXIO;
103: return;
104: }
105: ta->flags |= OPEN;
106: ta->flags &=~ (WRITTEN|WPROT|WONLY);
107: if ((*ta->port->mp_init)(rp->ctl, rp->ctype, 0, IDTA, taseql, tadg) == 0) {
108: u.u_error = ENXIO;
109: ta->flags &=~ OPEN;
110: return;
111: }
112: tacinit(ta, rp);
113: spl6();
114: wasoff = (ta->flags & ONLINE) == 0;
115: if ((ta->flags & ONLINE) == 0)
116: taonline(ta, rp);
117: spl0();
118: if ((ta->flags & ONLINE) == 0) {
119: u.u_error = ENXIO;
120: ta->flags &=~ OPEN;
121: return;
122: }
123: if ((ta->flags & WPROT) && (flag & FWRITE)) {
124: u.u_error = ENODEV;
125: if (!NOREW(dev))
126: tacmd(unit, 1, OPAVL, 0, 0);
127: ta->flags &=~ (OPEN|ONLINE);
128: return;
129: }
130: ta->dens = (1<<DENS(dev));
131: if (tacmd(unit, 0, OPGUS, 0, 0) /* fill in language in dens */
132: || tacmd(unit, 0, OPSUC, NOCACHE(dev)?0:UFWBK, wasoff?ta->dens:0)) {
133: u.u_error = ENXIO;
134: if (!NOREW(dev))
135: tacmd(unit, 1, OPAVL, 0, 0);
136: ta->flags &=~ (OPEN|ONLINE);
137: return;
138: }
139: if ((flag & (FREAD|FWRITE)) == FWRITE)
140: ta->flags |= WONLY;
141: }
142:
143: taclose(dev)
144: {
145: register struct tatape *ta;
146: int unit;
147:
148: unit = UNIT(dev);
149: ta = &tatape[unit];
150: if (ta->flags & ONLINE) {
151: if (ta->flags & (WONLY|WRITTEN)) {
152: tacmd(unit, 0, OPWRM, 0, 0);
153: tacmd(unit, 0, OPWRM, 0, 0);
154: tacmd(unit, 0, OPPOS, 0, -1);
155: }
156: /* annoyance: OPAVL always rewinds. */
157: if (!NOREW(dev))
158: tacmd(unit, 1, OPAVL, 0, 0);
159: }
160: ta->flags &=~ OPEN;
161: }
162:
163: /*
164: * send some non-io command to a tape drive
165: * op is the MSCP opcode;
166: * p0 and p1 are some parameters
167: * if async == 0, don't return until command does
168: */
169:
170: #define TWPRI PZERO
171: #define TCPRI (PZERO+1)
172:
173: static
174: tacmd(dev, async, op, p0, p1)
175: {
176: register struct mscmd *mp;
177: register struct tatape *ta;
178: register struct msaddr *rp;
179: register s;
180: register err;
181:
182: ta = &tatape[dev];
183: rp = &taaddr[dev];
184: if ((ta->flags & ONLINE) == 0)
185: return (1);
186: mp = (*ta->port->mp_get)(rp->ctl);
187: bzero((caddr_t)mp, sizeof(struct mscmd)); /* clear reserved fields */
188: mp->m_crf = ++tarefno;
189: mp->m_unit = rp->unit;
190: mp->m_opcd = op;
191: mp->m_mod = MDCSX;
192: switch (op) {
193: case OPPOS: /* position: type, nobjs */
194: if (p1 < 0) {
195: p1 = -p1;
196: mp->m_mod |= MDREV;
197: }
198: if (p0 == -1) { /* -1 == rewind */
199: mp->m_mod |= MDREW;
200: mp->m_mod |= p1; /* hack */
201: }
202: else if (p0 == 0) /* 0 == skip files */
203: mp->m_fcnt = p1;
204: else { /* 1 == skip records */
205: mp->m_mod |= MDOBJ;
206: mp->m_rcnt = p1;
207: }
208: break;
209:
210: case OPSUC: /* set unit char: unit flags, density */
211: mp->m_unfl |= p0;
212: mp->m_fmt = p1;
213: break;
214:
215: case OPGUS: /* get unit status */
216: mp->m_mod = p0; /* wretched TK50 */
217: break;
218:
219: default: /* anything else: modifiers, 0 */
220: mp->m_mod |= p0;
221: break;
222: }
223: s = spl6();
224: while (ta->cmdp) {
225: ta->flags |= NEEDCMD;
226: sleep((caddr_t)ta, TWPRI);
227: }
228: ta->cmdp = mp;
229: ta->flags &=~ (CMDERR|CMDDONE);
230: if (ta->flags & UNHAPPY) {
231: ta->flags &=~ UNHAPPY;
232: mp->m_mod |= MDCDL;
233: }
234: (*ta->port->mp_send)(rp->ctl, IDTA, mp);
235: if (async == 0) {
236: while ((ta->flags & CMDDONE) == 0)
237: if (tsleep((caddr_t)ta, TCPRI, 0) == TS_SIG)
238: break;
239: }
240: err = ((ta->flags & CMDERR) != 0);
241: ta->cmdp = NULL;
242: if (ta->flags & NEEDCMD) {
243: ta->flags &=~ NEEDCMD;
244: wakeup((caddr_t)ta);
245: }
246: splx(s);
247: return (err);
248: }
249:
250: int tastrategy();
251:
252: taread(dev)
253: {
254: physio(tastrategy, &tabuf[UNIT(dev)], dev, B_READ, minphys);
255: }
256:
257: tawrite(dev)
258: {
259: physio(tastrategy, &tabuf[UNIT(dev)], dev, B_WRITE, minphys);
260: }
261:
262: /*
263: * strategy routine;
264: * send the packet right away
265: */
266:
267: tastrategy(bp)
268: register struct buf *bp;
269: {
270: register struct tatape *ta;
271: register struct mscmd *mp;
272: register int unit;
273: register struct msaddr *rp;
274: int count;
275:
276: unit = UNIT(minor(bp->b_dev));
277: ta = &tatape[unit];
278: rp = &taaddr[unit];
279: count = bp->b_bcount;
280: spl6();
281: if ((ta->flags & ONLINE) == 0 && taonline(ta, rp) == 0) {
282: bp->b_flags |= B_ERROR;
283: iodone(bp);
284: spl0();
285: return;
286: }
287: mp = (*ta->port->mp_get)(rp->ctl);
288: mp->m_crf = ++tarefno;
289: mp->m_unit = rp->unit;
290: mp->m_opcd = (bp->b_flags & B_READ) ? OPRD : OPWR;
291: mp->m_mod = MDCSX;
292: if (ta->flags & UNHAPPY && (bp->b_flags & B_READ) == 0) {
293: ta->flags &=~ UNHAPPY;
294: mp->m_mod |= MDCDL;
295: }
296: mp->m_unfl = 0;
297: mp->m_bcnt = count;
298: /* seek on block device? later */
299: (*ta->port->mp_map)(rp->ctl, mp, bp);
300: bp->b_pkt = (struct buf *)mp;
301: bp->b_crf = mp->m_crf;
302: bp->b_next = NULL;
303: if (ta->actf)
304: ta->actl->b_next = bp;
305: else
306: ta->actf = bp;
307: ta->actl = bp;
308: if ((bp->b_flags & B_READ) == 0)
309: ta->flags |= WRITTEN;
310: (*ta->port->mp_send)(rp->ctl, IDTA, mp);
311: spl0();
312: }
313:
314: /*
315: * ioctl
316: * a subset of the berkeley ones
317: */
318:
319: taioctl(dev, cmd, addr, flag)
320: dev_t dev;
321: caddr_t addr;
322: {
323: struct mtop mt;
324: int func, p0, p1;
325:
326: switch (cmd) {
327: default:
328: u.u_error = ENOTTY;
329: break;
330: /* does anything use the other ones? */
331:
332: case MTIOCTOP:
333: if (copyin(addr, (caddr_t)&mt, sizeof(struct mtop)) < 0) {
334: u.u_error = EFAULT;
335: return;
336: }
337: if (mt.mt_op == MTWEOF) { /* oddball */
338: if ((flag & FWRITE) == 0) {
339: u.u_error = EBADF;
340: return;
341: }
342: while (mt.mt_count-- > 0)
343: if (tacmd(UNIT(dev), 0, OPWRM, 0, 0)) {
344: u.u_error = EIO;
345: return;
346: }
347: return;
348: }
349: if (mt.mt_op == MTRST) { /* another oddball */
350: (*tatape[UNIT(dev)].port->mp_init)(taaddr[UNIT(dev)].ctl, taaddr[UNIT(dev)].ctype, 1, IDTA, taseql, tadg);
351: return;
352: }
353: p1 = mt.mt_count;
354: func = OPPOS;
355: switch (mt.mt_op) { /* arcane arguments to tapos */
356: case MTBSF:
357: p1 = -p1;
358: case MTFSF:
359: p0 = 0;
360: break;
361:
362: case MTBSR:
363: p1 = -p1;
364: case MTFSR:
365: p0 = 1;
366: break;
367:
368: case MTREW:
369: p1 = 0;
370: p0 = -1;
371: break;
372:
373: case MTOFFL:
374: func = OPAVL;
375: p1 = 0;
376: p0 = MDUNL;
377: break;
378:
379: case MTNOP:
380: return; /* silly */
381: }
382: if (tacmd(UNIT(dev), 0, func, p0, p1))
383: u.u_error = EIO;
384: break;
385: }
386: }
387:
388: /*
389: * here when the port gets a sequential message
390: */
391: taseql(ctl, type, ep)
392: int ctl, type;
393: register struct msend *ep;
394: {
395: register struct buf *bp;
396: register struct tatape *ta;
397: register int unit;
398: register struct buf *obp;
399: int sts;
400:
401: if (ep->m_opcd == 0 && ep->m_sts == STRST) {
402: tareset(ctl, type);
403: return;
404: }
405: /* get rid of this wretched loop somehow */
406: for (unit = 0; unit < tacnt; unit++)
407: if (taaddr[unit].ctl == ctl
408: && taaddr[unit].ctype == type
409: && taaddr[unit].unit == ep->m_unit)
410: break;
411: if (unit >= tacnt) {
412: printf("tmscp stray unit: ctl%d typ%d ta%d sts %o opcode %o\n",
413: ctl, type, ep->m_unit, ep->m_sts, ep->m_opcd);
414: return;
415: }
416: ta = &tatape[unit];
417: if (ep->m_flgs & EFCDL)
418: ta->flags |= UNHAPPY;
419: switch (ep->m_opcd & 0377) {
420: case OPEND: /* eg invalid command */
421: printf("tmscp ctl%d ta%d ill cmd crf %d off %d\n", ctl,
422: ep->m_unit, ep->m_crf, ep->m_sts>>8);
423: if (ta->cmdp && ta->cmdp->m_crf == ep->m_crf)
424: goto fincmd;
425: /* else maybe it's a transfer; fall in */
426: case OPRD|OPEND:
427: case OPWR|OPEND:
428: for (bp = ta->actf, obp = NULL; bp; obp = bp, bp = bp->b_next)
429: if (ep->m_crf == bp->b_crf)
430: break;
431: if (bp == NULL) {
432: printf("ta%d stray end: crf %d sts x%x opcode 0%o\n",
433: unit, ep->m_crf, ep->m_sts, ep->m_opcd & 0377);
434: return;
435: }
436: if (obp)
437: obp->b_next = bp->b_next;
438: else
439: ta->actf = bp->b_next;
440: if (bp == ta->actl)
441: ta->actl = obp;
442: sts = ep->m_sts & STMSK;
443: if (sts == STAVL || sts == STOFL)
444: ta->flags &=~ ONLINE; /* help! */
445: bp->b_resid = bp->b_bcount - ep->m_bcnt;
446: if (sts == STTPM)
447: sts = STSUC; /* tape mark -> empty read */
448: if (sts != STSUC) {
449: bp->b_flags |= B_ERROR;
450: switch (sts) {
451: case STRDT:
452: case STOFL:
453: case STAVL:
454: case STWPR: /* well ... */
455: break;
456: default:
457: printf("err on ta%d block %D: sts 0%o flgs 0%o\n", unit, bp->b_blkno, ep->m_sts, ep->m_flgs);
458: }
459: }
460: if (ep->m_flgs & EFEOT && (bp->b_flags & B_READ) == 0) {
461: bp->b_error = ENOSPC;
462: bp->b_flags |= B_ERROR;
463: }
464: (*ta->port->mp_unmap)(ctl, (struct mscmd *)bp->b_pkt);
465: iodone(bp);
466: return;
467:
468: case OPGUS|OPEND:
469: ta->dens &= TFMASK;
470: ta->dens |= ep->m_menu & ~TFMASK;
471: goto fincmd;
472:
473: case OPAVL|OPEND:
474: if (ep->m_sts == STSUC) /* sic */
475: ta->flags &=~ ONLINE;
476: case OPWRM|OPEND:
477: case OPPOS|OPEND:
478: case OPFLS|OPEND:
479: case OPSUC|OPEND:
480: fincmd:
481: if ((ep->m_sts & STMSK) == STAVL || (ep->m_sts & STMSK) == STOFL)
482: ta->flags &=~ ONLINE;
483: if (ta->cmdp) {
484: ta->flags |= CMDDONE;
485: if ((ep->m_sts & STMSK) != STSUC) {
486: printf("ta%d: cmd 0%o sts 0%o flgs 0%o\n", unit, ep->m_opcd&0377, ep->m_sts, ep->m_flgs);
487: ta->flags |= CMDERR;
488: }
489: wakeup((caddr_t)ta);
490: }
491: return;
492:
493: case OPONL|OPEND:
494: tasonl(ta, ep);
495: return;
496:
497: case OPSCC|OPEND:
498: if ((ep->m_sts & STMSK) != STSUC)
499: printf("tmscp ctl%d typ%d: bad init\n", ctl, type);
500: return;
501:
502: default:
503: printf("stray tmscp msg ta%d opcd 0%o sts x%x\n",
504: unit, ep->m_opcd&0377, ep->m_sts&0177777);
505: return;
506: }
507: }
508:
509: /*
510: * controller was reset
511: * discard all pending io,
512: * awake all sleepers,
513: * mark everything offline
514: */
515:
516: tareset(ctl, type)
517: int ctl, type;
518: {
519: register int unit;
520: register struct tatape *ta;
521: register struct buf *bp, *nbp;
522:
523: for (unit = 0; unit < tacnt; unit++) {
524: if (taaddr[unit].ctl != ctl || taaddr[unit].ctype != type)
525: continue;
526: ta = &tatape[unit];
527: for (bp = ta->actf; bp; bp = nbp) {
528: nbp = bp->b_next;
529: (*ta->port->mp_unmap)(ctl, (struct mscmd *)bp->b_pkt);
530: bp->b_flags |= B_ERROR;
531: iodone(bp);
532: }
533: ta->actf = ta->actl = NULL;
534: ta->flags &=~ (ONLINE|WONLINE);
535: if (ta->cmdp)
536: ta->flags |= CMDDONE|CMDERR;
537: wakeup((caddr_t)ta);
538: }
539: }
540:
541: /*
542: * here with a datagram message
543: * explanations really shouldn't be in the driver
544: */
545:
546: static char *taevents[] = {
547: "ok",
548: "inv cmd",
549: "op aborted",
550: "offline",
551: "available",
552: "med fmt",
553: "write prot",
554: "comp err",
555: "data err",
556: "host buf access err",
557: "cntl err",
558: "drive err",
559: };
560: #define MAXEVT 0xb
561:
562: tadg(ctl, type, ep)
563: int ctl, type;
564: register struct mserl *ep;
565: {
566:
567: if (ep->l_evnt == STSEX) /* boring, at least for now */
568: return;
569: printf("ta%d ctl%d typ%d seq %d: %s err; fmt x%x ev x%x fl x%x\n",
570: ep->l_unit, ctl, type, ep->l_seq, /* phys unit, not log */
571: ep->l_flgs&(LFSUC|LFCON) ? "soft" : "hard",
572: ep->l_fmt, ep->l_evnt, ep->l_flgs&0377);
573: if ((ep->l_evnt & STMSK) <= MAXEVT)
574: printf("%s; ", taevents[ep->l_evnt & STMSK]);
575: switch (ep->l_fmt) {
576: case FMCNT:
577: /* now the thing should be marked disastrously bad */
578: printf("oops\n");
579: break;
580:
581: case FMBAD:
582: printf("host mem access; addr x%x\n", ep->l_badr);
583: break;
584:
585: case FMTAPE:
586: printf("lvl x%x retry x%x\n", ep->l_lvl, ep->l_rtry);
587: break;
588:
589: default:
590: printf("\n");
591: break;
592: }
593: }
594:
595: /*
596: * unit is believed offline
597: * try to bring it on
598: */
599:
600: static
601: taonline(ta, rp)
602: register struct tatape *ta;
603: register struct msaddr *rp;
604: {
605: register struct mscmd *mp;
606: int s;
607:
608: s = spl6();
609: if ((ta->flags & WONLINE) == 0) {
610: mp = (*ta->port->mp_get)(rp->ctl);
611: bzero((caddr_t)mp, sizeof(struct mscmd)); /* clear reserved fields */
612: mp->m_crf = ++tarefno;
613: mp->m_unit = rp->unit;
614: mp->m_opcd = OPONL;
615: mp->m_mod = MDCSX|MDXCL;
616: if (ta->flags & UNHAPPY) {
617: ta->flags &=~ UNHAPPY;
618: mp->m_mod |= MDCDL;
619: }
620: mp->m_unfl = 0;
621: mp->m_fmt = 0; /* ta->dens? */
622: (*ta->port->mp_send)(rp->ctl, IDTA, mp);
623: ta->flags |= WONLINE;
624: }
625: while (ta->flags & WONLINE)
626: tsleep((caddr_t)ta, PRIONL, 60);
627: splx(s);
628: if ((ta->flags & ONLINE) == 0)
629: return (0);
630: return (1);
631: }
632:
633: static
634: tasonl(ta, ep)
635: register struct tatape *ta;
636: register struct msend *ep;
637: {
638:
639: if (ta->flags & WONLINE) {
640: ta->flags &=~ WONLINE;
641: wakeup((caddr_t)ta);
642: }
643: if ((ep->m_sts & STMSK) != STSUC)
644: return;
645: ta->flags |= ONLINE;
646: if (ep->m_unfl & UFWPH)
647: ta->flags |= WPROT;
648: }
649:
650: /*
651: * controller init
652: * set characteristics to turn off host timeouts
653: */
654:
655: static
656: tacinit(ta, rp)
657: struct tatape *ta;
658: struct msaddr *rp;
659: {
660: register struct mscmd *mp;
661: register int s;
662:
663: mp = (*ta->port->mp_get)(rp->ctl);
664: bzero((caddr_t)mp, sizeof(struct mscmd)); /* clear reserved fields */
665: mp->m_crf = ++tarefno;
666: mp->m_opcd = OPSCC;
667: mp->m_mod = MDCSX;
668: mp->m_cntf = CFMSC | CFTHS;
669: mp->m_vrsn = MSCPVER;
670: s = spl6();
671: (*ta->port->mp_send)(rp->ctl, IDTA, mp);
672: splx(s);
673: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.