|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)ar.c 1.1 86/02/03 Copyr 1983 Sun Micro";
3: #endif
4:
5: /*
6: * Copyright (c) 1983 by Sun Microsystems, Inc.
7: */
8:
9: /*
10: * Standalone Driver for Archive Intelligent Streaming Tape
11: */
12: #include "saio.h"
13: #include "param.h"
14: #include "../sundev/arreg.h"
15: #include "ardef.h"
16:
17: #define min(a,b) ((a) < (b) ? (a) : (b))
18:
19: int ardebug = 0;
20: #define Dprintf if (ardebug) printf
21:
22: /* Trace all writes to control reg */
23: #define DebugTrace Dprintf(ar_ctrl_hdr, *(long*)(2+(char*)araddr), ar_bits)
24:
25: /* Define assorted debugging strings to save repeating them N times */
26: #ifdef DEBUG
27: char ar_bits[] = ARCH_LONG_CTRL_BITS;
28: char ar_ctrl_hdr[] = "ar* Bits: %b\n";
29: char ar_set_hdr[] = "ar* CMD: %x\n";
30: #endif DEBUG
31: char ar_stat_bits[] = ARCH_BITS;
32:
33: /*
34: * Standard I/O addresses.
35: */
36: #define NARADDR 2
37: u_long araddrs[] = { 0x200, 0x208};
38:
39: /*
40: * What resources we need to run
41: */
42: struct devinfo arinfo = {
43: sizeof (struct ardevice), /* I/O regs */
44: 0, /* no DMA */
45: sizeof (struct ar_softc), /* work area */
46: NARADDR,
47: araddrs,
48: MAP_MBIO,
49: DEV_BSIZE, /* transfer size */
50: };
51:
52: /*
53: * What facilities we export to the world
54: */
55: int aropen(), arclose(), arstrategy();
56: extern int xxboot(), xxprobe();
57:
58: struct boottab ardriver = {
59: "ar", xxprobe, xxboot, aropen, arclose, arstrategy,
60: "ar: Multibus Archive tape controller", &arinfo,
61: };
62:
63: /*
64: * Translation between generic tape commands and initial states of
65: * the Archive state machine.
66: */
67: enum ARstates ar_cmds[] = {
68: /* CLOSE */ CLOSEinit,
69: /* REWIND */ REWinit,
70: /* STATUS */ RDSTinit,
71: /* READ */ READinit,
72: /* WRITE */ WRinit,
73: /* WEOF */ WFMinit,
74: /* ERASE */ ERASEinit,
75: /* SELECT */ SELinit,
76: /* DELSELECT */ DESELinit,
77: /* TENSE */ TENSEinit,
78: /* SKIPFILE */ RFMinit,
79: /* CMD OK? */ CMDOKinit,
80: };
81:
82:
83: #define SPININIT 1000000
84: /*
85: * Initialize a controller
86: */
87: aropen(sip)
88: register struct saioreq *sip;
89: {
90: register struct ar_softc *sc;
91: register int count;
92: register struct ardevice *araddr;
93: int skip;
94:
95: sc = (struct ar_softc *)sip->si_devdata;
96: araddr = sc->sc_addr = (struct ardevice *)sip->si_devaddr;
97:
98: sc->sc_lastiow = 0;
99: sc->sc_state = IDLEstate;
100: /* sc->sc_status = 0; Doesn't work, so leave it alone. */
101: sc->sc_size = 0;
102: sc->sc_bufptr = (char *) 0x1ff001; /* very funny buf addr */
103: /* sc->sc_attached had better already be 1. */
104: sc->sc_initted = 0; /* until later */
105: sc->sc_opened = 0; /* until later */
106: sc->sc_drive = 0;
107: sc->sc_histate = 0;
108: /* sc->sc_addr had better already be initialized. */
109: sc->sc_qidle = 1;
110: sc->sc_eoflag = 0;
111: sc->sc_cmdok = 0;
112: sc->sc_selecteddev = -1;
113: /* When adding new fields to softc, be sure to initialize them here. */
114: /* FIXME, should initialize buffer headers here too */
115:
116: araddr->arunwedge = 1; /* Take it out of burst mode wedge */
117: araddr->arburst = 0;
118: araddr->arreq = 0;
119: araddr->arxfer = 0;
120: araddr->arcatch = 0;
121: araddr->arexcie = 0;
122: araddr->arrdyie = 0;
123:
124: /*
125: * If tape is up from previous system operation,
126: * take it down gently.
127: */
128: if (araddr->aronline) {
129: Dprintf("ar*init tape online\n");
130: araddr->aronline = 0; /* Writes TM (if writing) & rewinds */
131: }
132:
133: count = SPININIT;
134: while (!araddr->arrdy && !araddr->arexc && count)
135: count--;
136: if (count == 0) Dprintf("ar: Timeout waiting for Ready at %x\n", araddr);
137:
138: if (araddr->arrdy) Dprintf("ar*init arrdy on before reset\n");
139: if (araddr->arexc) Dprintf("ar*init arexc on before reset\n");
140:
141: /* Tape is ready or exceptional. Reset it for good measure. */
142: #ifdef PRF
143: Dprintf("ar*init about to arreset\n");
144: #endif PRF
145: araddr->arreset = 1;
146: #ifdef PRF
147: Dprintf("ar*init asserted arreset\n");
148: #endif PRF
149: DELAY(25); /* at least 13 usec */
150: araddr->arreset = 0;
151: #ifdef PRF
152: Dprintf("ar*init Reset complete\n");
153: #endif PRF
154:
155: count = SPININIT;
156: while (!araddr->arexc && count)
157: count--;
158: if (count == 0) {
159: Dprintf("ar: Timeout waiting for Exception after reset\n");
160: return (-1);
161: }
162:
163: /* Now read back status from the reset. */
164: sc->sc_initted = 1; /* Must do first so interrupt OK */
165: sc->sc_opened = 1; /* Must do first so interrupt OK */
166: araddr->aronline = 1; /* Must do first so RDST microcode doesn't
167: play games with arrdy line. See comments
168: in open(). */
169: if (arcmd(sc, AR_STATUS)) {
170: Dprintf("ar*init Error from command STATUS\n");
171: araddr->aronline = 0;
172: sc->sc_initted = 0; /* Try again on next open */
173: sc->sc_opened = 0; /* Try again on next open */
174: return (-1);
175: }
176:
177: /*
178: * FIXME, this is a kludge. open() won't select the drive unless
179: * the in-core status claims we are at BOT, since the tape drive
180: * will reject the command if indeed a tape was in use and is not
181: * at BOT. However, tapes at BOT after a Reset do not necessarily
182: * indicate BOT in their status. We should probably do a rewind
183: * here instead, if the tape exists.
184: */
185: sc->sc_status.BOT = 1; /* Pretend we're at BOT for open() */
186:
187: /*
188: * There is a problem in the Archive in that after each command,
189: * it goes thru a cleanup routine. If aronline is not asserted,
190: * this cleanup routine drops arrdy while it rewinds the tape
191: * to BOT. It deasserts arrdy for 90 us even if the tape is
192: * already at BOT. This causes us problems because we get a arrdy
193: * interrupt and then discover that arrdy is gone.
194: *
195: * The problem has been circumvented at the low level by checking
196: * for arrdy in the interrupt routine, and looping until it (or
197: * arexc) comes on. We attempt to fix the problem here, to avoid
198: * looping at SPL(), by having aronline always on when we are doing
199: * anything.
200: *
201: * The problem seems especially a problem for us on Select and Read
202: * Status commands. (That's because those are the only commands we
203: * do with aronline deasserted.)
204: *
205: * This info was obtained from Lou Domshy, Mgr. of Product Mgmt and
206: * Applications Engineering(?) at the Archive factory, 714-641-0279,
207: * on 1 December 1982, by John Gilmore of Sun Microsystems.
208: */
209: araddr->aronline = 1; /* Let ctrlr know we are doing a series */
210:
211: /*
212: * First select the drive we're interested in.
213: *
214: * Since the select command doesn't work when we aren't at BOT,
215: * we just have to hope the same drive is still selected as last
216: * time. FIXME. We should record this info in softc and keep it
217: * up to date. FIXME: also, I'm not happy about using status.BOT
218: * here, even tho it should always be up to date. -- JCGnu 22Nov82
219: */
220: sc->sc_cmdok = 0;
221: (void) arcmd(sc, AR_CMDOK); /* See if OK to issue cmds */
222: /*
223: * Now get its status and check on a few things.
224: */
225: if (sc->sc_cmdok) {
226: if (arcmd(sc, AR_STATUS)) { /* interrupted */
227: Dprintf("ar*open command STATUS error\n");
228: goto err;
229: }
230: if (sc->sc_status.NoDrive) {
231: printf("ar: no drive\n");
232: goto err;
233: }
234: if (sc->sc_status.NoCart) {
235: printf("ar: no cartridge in drive\n");
236: goto err;
237: }
238: }
239:
240: if ((sip->si_flgs&F_WRITE) && sc->sc_status.WriteProt) {
241: printf("ar: cartridge is write protected\n");
242: goto err;
243: }
244: sc->sc_lastiow = 0;
245:
246: skip = sip->si_boff;
247: while (skip--) {
248: arcmd(sc, AR_SKIPFILE);
249: arcmd(sc, AR_STATUS);
250: }
251: sc->sc_eoflag = 0;
252: Dprintf("ar*open exiting\n");
253: return (0);
254:
255: err:
256: arcmd(sc, AR_DESELECT);
257: araddr->aronline = 0;
258: sc->sc_opened = 0;
259: return (-1);
260: }
261:
262: /*
263: * Close tape device.
264: *
265: * If tape was open for writing or last operation was
266: * a write, then write two EOF's and backspace over the last one.
267: * Unless this is a non-rewinding special file, rewind the tape.
268: * Make the tape available to others.
269: */
270: arclose(sip)
271: struct saioreq *sip;
272: {
273: register struct ar_softc *sc = (struct ar_softc *)sip->si_devdata;
274: register struct ardevice *araddr = sc->sc_addr;
275:
276: /*
277: * Write file mark and rewind, by dropping aronline.
278: * FIXME. These 3 commands should be moved into AR_CLOSE
279: * in order that the user program can continue while the
280: * tape is rewinding.
281: */
282: arcmd(sc, AR_CLOSE); /* Shut down things */
283: araddr->aronline = 1; /* After rewind, set aronline */
284: /* See comments in open() about aronline and read status cmds */
285: /* FIXME, this might screw low level code if it affects arrdy */
286: arcmd(sc, AR_STATUS); /* Read block counts */
287: arcmd(sc, AR_DESELECT); /* Turn LED off */
288: sc->sc_selecteddev = -1;
289: sc->sc_eoflag = 0; /* Not at eof after rewind */
290: sc->sc_opened = 0; /* Available to be opened again */
291: Dprintf("ar*close exiting\n");
292: }
293:
294: arstrategy(sip, rw)
295: register struct saioreq *sip;
296: int rw;
297: {
298: register struct ar_softc *sc = (struct ar_softc *)sip->si_devdata;
299: int func = (rw == WRITE) ? AR_WRITE : AR_READ;
300:
301: if (sc->sc_eoflag) {
302: sc->sc_eoflag = 0;
303: return (0);
304: }
305: sc->sc_size = sip->si_cc;
306: sc->sc_bufptr = sip->si_ma;
307: if (arcmd(sc, func))
308: return (-1);
309: return (sip->si_cc);
310: }
311:
312: /*
313: * Begin execution of a device command for the device pointed to by
314: * sc. The command begins execution in state newstate.
315: *
316: * This is HARDWARE oriented software. It doesn't know or care of
317: * state of buffers, etc. Its result reflects what the hardware is
318: * doing, not what the software is doing.
319: *
320: * The device is assumed to be in one of the FIN or IDLE states:
321: * IDLEstate, FINstate, READfin, READidle, WRfin, or WRidle.
322: * This is a requirement, since various fields in sc have already
323: * been set up for us, and the use of those fields would conflict
324: * with their use by the interrupt routine if we weren't idle or fin.
325: *
326: * Our result is:
327: * 0 if the operation completed normally
328: * 1 if the operation completed abnormally
329: *
330: */
331: arcmd(sc, cmd)
332: register struct ar_softc *sc;
333: {
334: struct ardevice *araddr = sc->sc_addr;
335:
336: if (!sc->sc_opened)
337: return (-1);
338:
339: sc->sc_state = ar_cmds[cmd];
340:
341: for (;;) {
342: if (araddr->arexc) {
343: /*
344: * This interrupt is from the true level of arexc.
345: *
346: * An error has occurred. Deal with it somehow.
347: * If we are reading status, just do it; else do our own
348: * RDST to find out the problem, and cancel the current
349: * operation.
350: */
351: if (sc->sc_state == RDSTinit)
352: goto doit;
353: Dprintf("ar*intr arexc set, old state %x\n", sc->sc_state);
354: sc->sc_oldstate = sc->sc_state;
355: sc->sc_state = RDSTinit;
356: /*
357: * Clear EdgeReady and enable it so the next arrdy
358: * edge will be caught (possibly inside armachine()).
359: */
360: araddr->arcatch = 0;
361: araddr->arcatch = 1;
362: while (!armachine(sc)) {
363: /* Shouldn't happen! */
364: printf("ar*intr RDST did not return 1\n");
365: }
366: if (!sc->sc_status.FileMark) {
367: printf("ar: error %x\n",
368: *(u_short *)&sc->sc_status);
369: return (1);
370: }
371: /* Eof signaled now means that NEXT block is an EOF. */
372: sc->sc_eoflag = 1;
373: return (0);
374: }
375: if (araddr->arrdy) {
376:
377: doit:
378: araddr->arcatch = 0;
379: araddr->arcatch = 1;
380: if (armachine(sc))
381: return (0);
382: }
383: }
384: }
385:
386: /*
387: * State machine for archive tape drive controller.
388: * This actually accomplishes things w.r.t. the tape drive.
389: * Returns 0 if operation still in progress, 1 if finished.
390: * Note that we may take further interrupts after claiming that an
391: * operation is "finished". For example, we say a write is done when
392: * we have transferred the last byte of the block; but there will be
393: * an interrupt 5.5ms later to tell us it's ok to send the next block.
394: * Eventually, we will rewind the tape asynchronously after the file is
395: * closed, letting the user go free while it spins. FIXME: THIS CANNOT
396: * BE DONE until we clean up the high level code so it doesn't clobber
397: * our variables as it is setting up to call arstart_cmd().
398: */
399: armachine(sc)
400: register struct ar_softc *sc;
401: {
402: register struct ardevice *araddr = sc->sc_addr;
403: register int count, i, x;
404: register char *byteptr;
405:
406: Dprintf("ar*machine(%x, %x) state %x\n", sc, araddr, sc->sc_state);
407:
408: switch (sc->sc_state) {
409:
410: case CMDOKinit:
411: /*
412: * If we got here the command state is ok,
413: * i.e., not in the middle of a read or write.
414: */
415: sc->sc_state = IDLEstate;
416: sc->sc_cmdok = 1;
417: return (1);
418:
419: case CLOSEinit:
420: /* FIXME, this is time dependent and not documented in
421: the Archive manual */
422: araddr->aronline = 0; /* Drop online; we're done. */
423: if (araddr->arrdy)
424: goto IdleState; /* No interrupt will occur. */
425: else
426: goto FinState; /* Rewinding; wait for interrupt. */
427:
428: #ifdef FIXME
429: case CLOSEend:
430: /* This is entered from READidle or WRidle. */
431: araddr->aronline = 0; /* Drop it, causing rewind. */
432: goto FinState; /* Interrupt will signal end of rew. */
433: #endif
434:
435: case WFMinit:
436: sc->sc_status.BOT = 0;
437: araddr->ardata = ARCMD_WREOF;
438: araddr->arreq = 1;
439: goto CmdState;
440:
441: case RFMinit:
442: araddr->ardata = ARCMD_RDEOF;
443: araddr->arreq = 1;
444: goto CmdState;
445:
446: case REWinit:
447: araddr->ardata = ARCMD_REWIND;
448: araddr->arreq = 1;
449: goto CmdState;
450:
451: case TENSEinit:
452: araddr->ardata = ARCMD_TENSION;
453: araddr->arreq = 1;
454: goto CmdState;
455:
456: case ERASEinit:
457: araddr->ardata = ARCMD_ERASE;
458: araddr->arreq = 1;
459: goto CmdState;
460:
461: case SELinit:
462: araddr->ardata = ARCMD_LED | (1 << sc->sc_drive);
463: araddr->arreq = 1;
464: goto CmdState;
465:
466: case DESELinit:
467: araddr->ardata = 1 << sc->sc_drive;
468: araddr->arreq = 1;
469: goto CmdState;
470:
471: RDSTagain:
472: printf("ar: RDST gave Exception, retrying\n");
473: /* Fall thru... */
474:
475: case RDSTinit:
476: byteptr = (char *) &sc->sc_status;
477:
478: /* We could have either arrdy or arexc; remember which */
479: count = 0;
480: if (araddr->arrdy)
481: count = 1;
482: araddr->ardata = ARCMD_RDSTAT;
483: araddr->arreq = 1;
484:
485: /*
486: * Now wait for arrdy indicating command accepted.
487: * Check for Exception, if we started with arrdy.
488: * (It's not legal to do RDST all the time(!).)
489: */
490: while (!araddr->arrdy)
491: if (count && araddr->arexc)
492: goto RDSTagain;
493:
494: /* Negate arreq, wait for arrdy to drop. */
495: araddr->arcatch = 0; /* Clear arrdyedge */
496: araddr->arcatch = 1; /* Catch edge */
497: araddr->arreq = 0;
498:
499: /* Now xfer a byte or six. */
500: do {
501: /* Wait for edge of arrdy */
502: while (!araddr->arrdyedge)
503: if (araddr->arexc)
504: goto RDSTagain;
505: *byteptr++ = araddr->ardata;
506: araddr->arcatch = 0; /* Clear edge indicator */
507: araddr->arcatch = 1; /* Catch next one */
508: araddr->arreq = 1; /* Tell controller we have it */
509: /* Ready will fall within 250ns of our arreq, but
510: we're supposed to keep it high for 20us */
511: DELAY(30); /* at least 20 usec */
512: araddr->arreq = 0;
513: } while (byteptr <
514: (char *)(&sc->sc_status) + sizeof (sc->sc_status));
515: /*
516: * On exit from this loop, arcatch has been negated and
517: * asserted, so it will correctly reflect the leading edge
518: * of arrdy for the next command.
519: */
520: sc->sc_oldstate = sc->sc_state;
521: sc->sc_state = FINstate; /* Awaiting final interrupt */
522:
523: /* Dump status bytes after a command AR_STATUS */
524:
525: Dprintf("ar*RDST %b %d %d\n", *(unsigned short*)&sc->sc_status,
526: ar_stat_bits, sc->sc_status.SoftErrs, sc->sc_status.TapeStops);
527:
528: /* This code is obsolete since sc_qidle, and should be replaceable
529: by a simple branch to RdWrFin. However, that doesn't work, so
530: try this. JCGnu, 23Nov82 */
531: while (!araddr->arrdy)
532: if (araddr->arexc)
533: goto RDSTagain;
534: /* We leave the edge of Ready caught in EdgeReady, but IdleState will
535: disable interrupts on it. */
536: goto IdleState;
537:
538: case READcmd:
539: case WRcmd:
540: araddr->arreq = 0;
541: goto next;
542:
543: case READinit:
544: araddr->ardata = ARCMD_RDDATA;
545: araddr->arreq = 1;
546: goto next;
547:
548: case READburst:
549: /* Read a block of data from the tape drive. */
550: Dprintf("ar*READ addr %x count %x\n", sc->sc_bufptr, sc->sc_size);
551: sc->sc_status.BOT = 0;
552: while (!araddr->arrdy) {
553: if (araddr->arexc)
554: return (0); /* Not yet done */
555: Dprintf("ar*Read no READY\n");
556: }
557: araddr->arburst = 1; /* Begin block xfer */
558: count = min(sc->sc_size, AR_BSIZE);
559: byteptr = sc->sc_bufptr;
560: for (i=0; i<count; i++)
561: *byteptr++ = araddr->ardata; /* read data */
562: for (; i<AR_BSIZE; i++)
563: x = araddr->ardata; /* read junk */
564: araddr->arburst = 0;
565: sc->sc_oldstate = sc->sc_state;
566: sc->sc_state = READfin; /* Like FINstate sorta */
567: break;
568:
569: case WRinit:
570: araddr->ardata = ARCMD_WRDATA;
571: araddr->arreq = 1;
572: goto next;
573:
574: case WRburst:
575: /* Write a block of data to the tape drive. */
576: Dprintf("ar*WRITE addr %x count %x\n", sc->sc_bufptr, sc->sc_size);
577: while (!araddr->arrdy) {
578: if (araddr->arexc)
579: return (0); /* Not done yet */
580: Dprintf("ar*Write no READY\n");
581: }
582: araddr->arburst = 1; /* Begin block xfer */
583: count = AR_BSIZE;
584: byteptr = sc->sc_bufptr;
585: while (count--)
586: araddr->ardata = *byteptr++;
587: araddr->arburst = 0;
588: sc->sc_oldstate = sc->sc_state;
589: sc->sc_state = WRfin; /* Like FINstate sorta */
590: Dprintf("ar*machine exiting done in state %x\n", sc->sc_state);
591: /*
592: * This code is a copy of the code at the end of this
593: * switch statement, except that it returns 1 (operation
594: * completed) instead of 0 (more needs doing)
595: */
596: araddr->arrdyie = 1;
597: araddr->arexcie = 1;
598: return (1);
599:
600: case CMDstate:
601: /* All commands that stop interacting once you say "do it" */
602: araddr->arreq = 0; /* Done with command */
603: goto FinState; /* Final interaction for this cmd */
604:
605: IdleState: /* Drive is idle; set IDLEstate and disable */
606: sc->sc_oldstate = sc->sc_state;
607: sc->sc_state = IDLEstate;
608: goto DisAble;
609:
610: case WRfin: /* Entry after writing a block */
611: case READfin: /* Entry after reading a block */
612: case FINstate: /* Entry after any other command */
613: /*
614: * Go to next sequential state - WRidle, READidle, IDLEstate.
615: * Disable interrupts, and return. arstart_cmd() will later
616: * put us into READ/WRburst or some commandinit state.
617: */
618: sc->sc_oldstate = sc->sc_state;
619: sc->sc_state = (enum ARstates)(1 +(int)sc->sc_state);
620: DisAble:
621: Dprintf("ar*machine idling\n");
622: araddr->arrdyie = 0; /* Negate arrdy interrupt */
623: return (1); /* Tell caller op is done */
624:
625: case WRidle: /* Writing blocks, but none to write now */
626: case READidle: /* Reading blocks, but don't need one now */
627: case IDLEstate: /* Issuing commands, but don't have one now */
628: /* This can only happen if software triggers us. */
629: printf("ar: triggerred at idle %x\n", sc->sc_state);
630: goto DisAble; /* Turn off interrupt enable again */
631:
632: default:
633: printf("ar: invalid state %d\n", sc->sc_state);
634: goto FinState; /* Is this reasonable? */
635:
636: next:
637: /* Go to next sequential state */
638: sc->sc_oldstate = sc->sc_state;
639: sc->sc_state = (enum ARstates)(1 +(int)sc->sc_state);
640: break;
641:
642: FinState:
643: sc->sc_oldstate = sc->sc_state;
644: sc->sc_state = FINstate;
645: break;
646:
647: CmdState:
648: sc->sc_oldstate = sc->sc_state;
649: sc->sc_state = CMDstate;
650: break;
651:
652: }
653:
654: Dprintf("ar*machine exiting in state %x\n", sc->sc_state);
655:
656: /* Go to next state on the next leading edge of arrdy. */
657: araddr->arrdyie = 1; /* Interrupt on arrdy leading edge */
658: araddr->arexcie = 1; /* Interrupt on arexc too */
659: /* FIXME. Figure out where to set and unset, leave alone otherwise. */
660:
661: return (0);
662: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.