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