|
|
1.1 root 1: /* %M% %I% %G% */
2:
3: /*
4: * TM tape driver
5: */
6: #include "../h/param.h"
7: #include "../h/buf.h"
8: #include "../h/dir.h"
9: #include "../h/conf.h"
10: #include "../h/user.h"
11: #include "../h/file.h"
12: #include "../h/map.h"
13: #include "../h/pte.h"
14: #include "../h/uba.h"
15:
16: extern struct device *tmaddr;
17: extern int ntm;
18: extern char tm_flags[]; /* used for T_WRITTEN flag */
19: extern char tm_openf[]; /* open flag for device */
20: extern daddr_t tm_blkno[]; /* pointer to current block on tape */
21: extern daddr_t tm_nxrec[]; /* pointer to end of file on tape */
22:
23: struct device {
24: short tmer; /* status register*/
25: short tmcs; /* command register */
26: short tmbc; /* byte (read/write) record (space) counter */
27: unsigned short tmba; /* current memory address counter */
28: short tmdb; /* data buffer register */
29: short tmrd; /* tu10 read lines */
30: };
31:
32: #define b_repcnt b_bcount /* Command repetition counter */
33: #define b_command b_resid /* Command to do */
34: #define b_status b_resid /* Status after a tcommand */
35:
36: struct buf tmtab; /* block device list header */
37: struct buf ctmbuf; /* control semaphore*/
38: struct buf rtmbuf; /* raw i/o device list header */
39:
40: #define U_REWD 04 /* Rewind on close */
41: #define U_DUALD 08 /* Dual density */
42:
43: /* CONTROL FLAGS */
44: #define GO 01 /* initiate command and reset CU RDY */
45: #define RCOM 02 /* read */
46: #define WCOM 04 /* write */
47: #define WEOF 06 /* write eof mark */
48: #define SFORW 010 /* space forward */
49: #define SREV 012 /* space reverse */
50: #define WIRG 014 /* write with extended irg; for write errors */
51: #define REW 016 /* rewind */
52: #define NOP 0100 /* nop = interrupt enable */
53: #define IENABLE 0100 /* enable interrupts */
54: #define DCLR 010000 /* Drive clear -- reset any hard error bits */
55: #define D800 060000 /* 9-channel, 800 bpi density */
56: #define D1600 0117777 /* 9-channel, 1600 bpi density*/
57:
58: /* STATUS FLAGS */
59: #define TUR 1 /* tape unit ready */
60: #define RWS 02 /* rewind in progress--set on first rewind int*/
61: #define WL 04 /* write lock bit -- read ring off tape */
62: #define GAPSD 010 /* gap settle down bit */
63: #define RLE 0100 /* record length error on read */
64: #define CRDY 0200 /* control unit ready */
65: #define EOF 040000 /* end of file */
66: #define HARD 0100000 /* ILC (could be more if we trusted the UBA) */
67:
68: /* DRIVER MODES */
69: #define SSEEK 1 /* seek mode */
70: #define SIO 2 /* sequential i/o mode */
71: #define SCOM 3 /* command mode */
72:
73: #define T_WRITTEN 1 /* device flag for eof writes */
74: #define T_WANTED 02 /* wait for rewind flag*/
75:
76: tmopen(dev, flag)
77: dev_t dev;
78: int flag;
79: {
80: register unit, ds;
81:
82: unit = minor(dev) & 03;
83: if (tm_openf[unit])
84: {
85: u.u_error = ENXIO;
86: return;
87: }
88: tm_blkno[unit] = 0;
89: tm_flags[unit] = 0;
90: tm_nxrec[unit] = 65535;
91:
92: tmtab.b_flags |= B_TAPE;
93:
94: ds = tcommand(dev, NOP, 1);
95:
96: if ((ds & TUR) == 0) {
97: while (ds = tcommand(dev, NOP, 1) & RWS) {
98: /* sleep during rewind initiated during prior IO */
99: tm_flags[ntm11] |= T_WANTED;
100: sleep((caddr_t)&tm_flags[ntm11],PRIBIO);
101: }
102: }
103:
104: while ((ds = tcommand(dev, NOP, 1)) & GAPSD)
105: continue;
106:
107: if ((ds&TUR)==0 || (flag && ds&WL)) {
108: /* Offline or needs a write ring */
109: tmaddr->tmcs = DCLR|GO;
110: u.u_error = EIO;
111: }
112: /* tm_openf may have value -1 if certain hardware conditions came up */
113: tm_openf[unit] = (u.u_error == 0);
114: }
115:
116: tmclose(dev, flag)
117: register dev_t dev;
118: register flag;
119: {
120: register unit;
121:
122: unit = minor(dev)&03;
123: tm_openf[unit]++;
124: if (flag == FWRITE ||
125: ((flag&FWRITE) && (tm_flags[minor(dev)&03] & T_WRITTEN))) {
126: (void) tcommand(dev, WEOF, 2);
127: (void) tcommand(dev, SREV, 1);
128: }
129: if ((minor(dev)&U_REWD) == 0)
130: /* rewind if bit 2 is set in minor */
131: (void) tcommand(dev, REW, 1);
132: tm_openf[minor(dev)&03] = 0;
133: }
134:
135: tcommand(dev, com, cnt)
136: register dev_t dev;
137: register com, cnt;
138: {
139: register struct buf *bp;
140:
141: bp = &ctmbuf;
142: (void) spl5();
143: while (bp->b_flags&B_BUSY)
144: {
145: bp->b_flags |= B_WANTED;
146: sleep((caddr_t)bp, PRIBIO);
147: }
148: bp->b_flags = B_BUSY|B_READ;
149: (void) spl0();
150:
151: bp->b_dev = dev;
152: bp->b_repcnt = -cnt;
153: bp->b_command = com;
154: bp->b_blkno = 0;
155:
156: tmstrategy(bp);
157:
158: iowait(bp);
159: if (bp->b_flags&B_WANTED)
160: wakeup((caddr_t)bp);
161: bp->b_flags = 0;
162: return(bp->b_status);
163: }
164:
165: tmstrategy(bp)
166: register struct buf *bp;
167: {
168: register daddr_t *p;
169:
170: if (bp != &ctmbuf) {
171: p = &tm_nxrec[minor(bp->b_dev)&03];
172: if (*p <= dbtofsb(bp->b_blkno)) {
173: if (*p < dbtofsb(bp->b_blkno)) {
174: /* Blkno past EOF */
175: bp->b_flags |= B_ERROR;
176: iodone(bp);
177: return;
178: }
179: if (bp->b_flags&B_READ) {
180: /* Reading at EOF */
181: clrbuf(bp);
182: bp->b_resid = bp->b_bcount;
183: iodone(bp);
184: return;
185: }
186: }
187: if ((bp->b_flags&B_READ) == 0) {
188: tm_flags[minor(bp->b_dev)&03] |= T_WRITTEN;
189: /* Change software location of EOF */
190: *p = dbtofsb(bp->b_blkno) + 1;
191: }
192: }
193:
194: bp->av_forw = 0;
195:
196: (void) spl5();
197: if (tmtab.b_actf == NULL)
198: tmtab.b_actf = bp;
199: else
200: tmtab.b_actl->av_forw = bp;
201: tmtab.b_actl = bp;
202: if (tmtab.b_active == NULL)
203: tmstart();
204: (void) spl0();
205: }
206:
207: tmstart()
208: {
209: register struct buf *bp;
210: register com;
211: register unit;
212: register daddr_t blkno;
213:
214: loop:
215: if ((bp = tmtab.b_actf) == 0)
216: return;
217: unit = minor(bp->b_dev)&03;
218: blkno = tm_blkno[unit];
219: if (tm_openf[unit] < 0 || (tmaddr->tmcs & CRDY) == NULL) {
220: bp->b_flags |= B_ERROR;
221: goto next;
222: }
223: com = IENABLE | (unit << 8) | GO;
224:
225: if (minor(bp->b_dev) & U_DUALD)
226: com &= D1600;
227: else
228: com |= D800;
229:
230: if (bp == &ctmbuf) {
231: if (bp->b_command == NOP) {
232: /* return device status */
233: bp->b_status = tmaddr->tmer;
234: goto next;
235: }
236: com |= bp->b_command;
237: tmtab.b_active = SCOM;
238: if(bp->b_command == SFORW || bp->b_command == SREV)
239: tmaddr->tmbc = bp->b_repcnt;
240: tmaddr->tmcs = com;
241: return;
242: }
243: if (blkno != dbtofsb(bp->b_blkno)) {
244: /* Block mode, seek to correct block */
245: tmtab.b_active = SSEEK;
246: if (blkno < dbtofsb(bp->b_blkno)) {
247: com |= SFORW;
248: tmaddr->tmbc = blkno - dbtofsb(bp->b_blkno);
249: } else {
250: com |= SREV;
251: tmaddr->tmbc = dbtofsb(bp->b_blkno) - blkno;
252: }
253: tmaddr->tmcs = com;
254: return;
255: }
256: if (tmtab.b_un.b_addr == 0)
257: tmtab.b_un.b_addr = (caddr_t)ubasetup(bp,1);
258:
259: /* Set high 2 bits of UNIBUS address */
260: com |= (((long)tmtab.b_un.b_addr >> (16-4)) & 060);
261:
262: tmtab.b_active = SIO;
263: com |= ((bp->b_flags & B_READ) ? RCOM : ((tmtab.b_errcnt) ? WIRG : WCOM ));
264: tmaddr->tmbc = -bp->b_bcount;
265: tmaddr->tmba = ((int)tmtab.b_un.b_addr & 0xffff);
266: tmaddr->tmcs = com;
267: return;
268:
269: next:
270: if (tmtab.b_un.b_addr != 0) {
271: ubafree(tmtab.b_un.b_addr);
272: tmtab.b_un.b_addr = 0;
273: }
274: tmtab.b_actf = bp->av_forw;
275: iodone(bp);
276: goto loop;
277: }
278:
279: tmintr()
280: {
281: register struct buf *bp;
282: register state, unit;
283:
284: if (tm_flags[ntm11] & T_WANTED) {
285: /* wake up any rewind sleepers*/
286: tm_flags[NUNIT] &= ~T_WANTED;
287: wakeup((caddr_t)&tm_flags[NUNIT]);
288: }
289: if ((bp = tmtab.b_actf) == NULL)
290: return;
291:
292: unit = minor(bp->b_dev)&03;
293: state = tmtab.b_active;
294: tmtab.b_active = NULL;
295: if (tmaddr->tmcs < 0) {
296: /*
297: * On error, first wait for gap shutdown
298: */
299: while(tmaddr->tmer & GAPSD)
300: ;
301: if (tmaddr->tmer&EOF) {
302: /* EOF, set nxrec to sought block */
303: tm_nxrec[unit] = dbtofsb(bp->b_blkno);
304: state = SCOM;
305: tmaddr->tmbc = -bp->b_bcount;
306: goto out;
307: }
308: if ((bp->b_flags&B_READ) && (tmaddr->tmer&(HARD|RLE)) == RLE)
309: goto out;
310: if ((tmaddr->tmer&(HARD|EOF)) == NULL && state==SIO) {
311: /* if not a hard error or eof and in sequential mode */
312: if (++tmtab.b_errcnt < 3) {
313: if((tmaddr->tmer&~RLE) != 0xC0)
314: tm_blkno[unit]++;
315: else
316: printf("TM UBA late error\n");
317: if(tmtab.b_un.b_addr) {
318: ubafree(tmtab.b_un.b_addr);
319: tmtab.b_un.b_addr = 0;
320: }
321: /* retry: skip reverse one and do IO again */
322: tmstart();
323: return;
324: }
325: } else if (tm_openf[unit]>0 && bp!=&rtmbuf &&
326: (tmaddr->tmer&EOF)==0)
327: tm_openf[unit] = -1;
328: deverror(bp, tmaddr->tmer&0xffff, tmaddr->tmcs&0xffff);
329: bp->b_flags |= B_ERROR;
330: state = SIO;
331: }
332: out:
333: switch (state) {
334:
335: case SIO:
336: tm_blkno[unit]++;
337: /* fall into ... */
338: case SCOM:
339: if (bp == &ctmbuf)
340: if (bp->b_command == SFORW || bp->b_command == SREV) {
341: if (bp->b_command == SREV)
342: tm_blkno[unit] -= -bp->b_repcnt;
343: else
344: tm_blkno[unit] += -bp->b_repcnt;
345: } else if (++bp->b_repcnt)
346: break;
347: tmtab.b_errcnt = 0;
348: tmtab.b_actf = bp->av_forw;
349: bp->b_resid = -tmaddr->tmbc;
350: if(tmtab.b_un.b_addr != 0) {
351: ubafree(tmtab.b_un.b_addr);
352: tmtab.b_un.b_addr = 0;
353: }
354: iodone(bp);
355: break;
356: case SSEEK:
357: tm_blkno[unit] = dbtofsb(bp->b_blkno);
358: break;
359: default:
360: return;
361: }
362: tmstart();
363: }
364:
365: tmread(dev)
366: {
367:
368: tmphys(dev);
369: physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
370: }
371:
372: tmwrite(dev)
373: {
374:
375: tmphys(dev);
376: physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
377: }
378:
379: tmphys(dev)
380: {
381: register unit;
382: register daddr_t a;
383:
384: unit = minor(dev) & 03;
385: a = dbtofsb(u.u_offset >> 9);
386: tm_blkno[unit] = a;
387: tm_nxrec[unit] = a + 1;
388: }
389:
390: #define NTMIOCTRL (sizeof tmiolist)
391:
392: char tmiolist[] =
393: {
394: SFORW, /* 0 = skip forward */
395: SREV, /* 1 = skip reverse */
396: WEOF, /* 2 = Write EOF */
397: REW, /* 3 = rewind */
398: 0, /* 4 = skip forward file */
399: 0 /* 5 = skip reverse file */
400: };
401:
402: tmioctrl(dev, cmd, arg, flag)
403: register dev_t dev;
404: register int cmd, flag, arg;
405: {
406: register ioctr;
407:
408: if((unsigned)cmd >= NTMIOCTRL || arg <= 0)
409: u.u_error = ENXIO;
410: else {
411: if(cmd > 3) {
412: /* Skip forward/reverse file(s) */
413: cmd -= 3;
414: ioctr = arg;
415: arg = -1;
416: } else
417: ioctr = 1;
418: do
419: (void) tcommand(dev, tmiolist[cmd], arg);
420: while (--ioctr);
421: }
422: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.