Bell 32V development
[unix-history] / usr / src / standalone / d2tcpy.c
CommitLineData
d52f1552
TL
1# define MIN(a,b) (a<b?a:b)
2# define RP6CYL 815 /* no. RP06 cylinders/pack */
3# define RP6TRK 19 /* no. tracks/cyl */
4# define RP6SEC 22 /* no. sectors/track */
5# define RP6ST (RP6TRK*RP6SEC) /* no. sectors/cyl */
6# define MAXSEC (RP6CYL*RP6TRK*RP6SEC) /* sectors/pack */
7# define M0 0x20010000 /* phys addr MBA 0 */
8# define M1 0x20012000 /* phys addr MBA 1 */
9# define M0_cr (M0+4) /* MBA 0 control reg addr */
10# define M1_cr (M1+4) /* MBA 1 control reg addr */
11# define M0_map (M0+0x800) /* start MBA 0 map reg's */
12# define M1_map (M1+0x800) /* start MBA 1 map reg's */
13# define M0_var (M0+0xc) /* MBA 0 virt addr reg */
14# define M1_var (M1+0xc) /* MBA 1 virt addr reg */
15# define M0_bc (M0+0x10) /* MBA 0 byte count reg */
16# define M1_bc (M1+0x10) /* MBA 1 byte count reg */
17# define MBAinit 01 /* MBA init bit */
18/* */
19# define TM (M1+0x400) /* base for TM02/TE16 reg's */
20# define RP (M0+0x400) /* base for RP06 reg's, drive 0 */
21/* */
22# define TM_tc (TM+0x24) /* TM02 tape control reg */
23# define TM_cs1 (TM+0) /* TM02 control 1 reg */
24# define TM_ds (TM+4) /* status reg */
25# define TM_fc (TM+0x14) /* TM02 frame count reg */
26/* */
27# define RP_cr 0 /* RP06 control reg offset, longword */
28# define RP_sr 1 /* RP06 status reg offset */
29# define RP_stk 5 /* RP06 sector/track reg offset */
30# define RP_off 011 /* RP offset reg */
31# define RP_cyl 10 /* RP06 cylinder reg offset */
32/* */
33# define RP_GO 1 /* go bit */
34# define RP_RD 070 /* RP06 read function code */
35# define RP_WR 060 /* RP06 write function code */
36# define RP_DC 010 /* drive clear function code */
37# define RP_FMT 0x1000 /* format bit in RP offset reg */
38# define RP_RIP 020 /* Read-in Preset function code */
39# define RP_MOL 0x1000 /* medium online bit in status */
40# define RP_DRY 0200 /* drive ready, status reg */
41# define RP_ERR 040000 /* composite error, status reg */
42/* */
43# define TM_GO 1 /* TM02 go bit */
44# define TM_DCLR 010 /* TM02 drive clear function code */
45# define TM_SFWD 030 /* space forward function code */
46# define TM_WRTF 060 /* write forward function code */
47# define TM_REDF 070 /* read forward function code */
48# define TM_RWND 06 /* TM02 Rewind */
49# define TM_WEOF 026 /* write end of file function */
50# define TCHAR 01300 /* TM02/TE16 drive 0 ,800 BPI,PDP11,etc. */
51# define TM_DRDY 0200 /* TM02/drive ready,status reg */
52# define TM_ERR 040000 /* TM02 composite error, status reg */
53/* */
54# define RXCS 32 /* receiver control/staus */
55# define RXDB 33 /* receiver data */
56# define TXCS 34 /* transmitter control/status */
57# define TXDB 35 /* transmitter data */
58# define RXCS_DONE 0x80 /* receiver done */
59# define TXCS_RDY 0x80 /* transmitter ready */
60/* */
61# define BUFSIZ 5120 /* max tape block size = input buffer size */
62# define MAXUNI 1
63# define NL 012
64# define CR 015
65/* */
66char input[BUFSIZ] ; /* tape input buffer */
67struct { int reg ; } ;
68int blksiz ,tapoff , dskoff , wsize , dblks ;
69int count;
70unsigned int ins , outs ;
71unsigned short nread , bytoff , error ;
72int *RPptr , dunit ; /* ptr to start of RP reg's for desired drive */
73main() {
74/*
75* Stand-alone program to copy TM02/TE16 drive 0 mag tape to
76* RP06 disc.
77* User specifies tape block size (must be multiple of 512), tape
78* offset (tape blocks), disc unit no., disc offset (512-byte
79* blocks) and count of tape blocks to be transferred.
80*/
81int getcon() , putstr() , a2l() , l2a() ;
82
83putlin("d2tcpy : Disk-to-Tape Copy") ;
84putnl() ;
85
86bsize :
87if (putstr("tape block size : ")) goto fini ;
88if (getcon(input)) goto fini ;
89putnl() ;
90blksiz = a2l(input) ;
91if ((blksiz <= 0) || (blksiz > BUFSIZ)) goto bsize ;
92if (blksiz%512) goto bsize ; /* block size must be 512 multiple */
93M0_cr->reg = MBAinit ; /* MBA 0 init */
94M1_cr->reg = MBAinit ; /* MBA 1 init */
95
96TM_tc->reg = TCHAR ; /* TE16,drive 0 ,800 BPI, PDP11, odd parity,
97 abort on error */
98TM_cs1->reg = TM_DCLR | TM_GO ; /* clear tape drive 0 */
99if (terror()) goto taperr ;
100
101toff :
102if (putstr("tape offset : ")) goto fini ;
103if (getcon(input)) goto fini ;
104putnl() ;
105tapoff = a2l(input) ;
106if (tapoff < 0) goto toff ;
107if (taprew()) goto taperr ;
108if (tapspc(tapoff)) goto taperr ;
109
110dun :
111if (putstr("disk unit : ")) goto fini ;
112if (getcon(input)) goto fini ;
113putnl() ;
114dunit = a2l(input) ;
115if ((dunit > MAXUNI) || (dunit < 0)) goto dun ;
116
117doff :
118if (putstr("disc offset : ")) goto fini ;
119if (getcon(input)) goto fini ;
120putnl() ;
121dskoff = a2l(input) ;
122if ((dskoff < 0) || (dskoff > MAXSEC-1)) goto doff ;
123
124gknt :
125if (putstr("no. of input blocks : ")) goto fini ;
126if (getcon(input)) goto fini ;
127putnl() ;
128count = a2l(input) ;
129if (count < 0) goto gknt ;
130
131error = 0 ;
132
133if (init()) goto bsize ;
134
135while ((error == 0) && (count>0)) {
136 if (dread()) {
137 putlin("disc i/o error") ;
138 goto ioerr ;
139 }
140 ins++ ; /* count of disk blocks input */
141 if (twrite()) {
142 taperr :
143 putlin("tape i/o error") ;
144 ioerr :
145 error++ ;
146 continue ;
147 }
148 outs =+ dblks ; /* count of tape blocks output */
149 count -= nread ;/* dec no. blocks read */
150}
151
152fini :
153TM_cs1->reg = TM_WEOF | TM_GO;
154twait();
155TM_cs1->reg = TM_RWND | TM_GO;
156twait();
157return(0) ;
158}
159
160/* */
161
162putstr(csp)
163register char *csp ;
164{
165if (putcon(csp)) return(-1) ;
166return(0) ;
167}
168
169/* */
170
171putlin(sptr)
172register char *sptr ;
173{
174if (putcon(sptr)) return(-1) ;
175if (putnl()) return(-1) ;
176return(0) ;
177}
178
179/* */
180
181putnl()
182{
183if (putcon("\r\n")) return(-1) ;
184return(0) ;
185}
186
187/* */
188
189putcon(csp)
190register char *csp ;
191{
192/*
193* Function to output null-terminated string pointed to
194* by 'csp' to the VAX LSI terminal.
195*/
196register c ;
197
198c = 0 ;
199while (c = (*csp++)) putc(c) ;
200return(0) ;
201}
202
203/* */
204
205putc(c)
206{
207/* wait for LSI printer to be ready */
208while ((mfpr(TXCS) & TXCS_RDY) == 0) ;
209/* output character */
210mtpr(TXDB,c&0177) ;
211}
212
213/* */
214
215getcon(cs)
216register char *cs ;
217{
218/*
219* Function to return char's from VAX LSI keyboard to
220* char array 'cs' - input stops when CR or LF received -
221* null char appended to end of input
222*/
223register int c , c2 ;
224int getc() ;
225
226inloop :
227 c = getc() ; /* get 1 char from terminal */
228 putc(c) ; /* echo char */
229 if ((c == NL) || (c == CR)) {
230 putc(CR) ;
231 putc(0) ;
232 putc(NL) ;
233 (*cs++) = '\0' ;
234 return(0) ;
235 }
236 else {
237 (*cs++) = c ;
238 goto inloop ;
239 }
240}
241
242/* */
243
244getc()
245{
246/*
247* Return char from VAX LSI terminal char buffer
248*/
249int mfpr() ;
250
251/* Wait for receiver done (user entered char)
252*/
253while ((mfpr(RXCS) & RXCS_DONE) == 0) ;
254return (mfpr(RXDB) & 0177) ; /* return char from receiver buffer */
255}
256
257/* */
258
259mtpr(regno,value)
260{
261 asm(" mtpr 8(ap),4(ap)") ;
262}
263
264/* */
265
266mfpr(regno)
267{
268 asm(" mfpr 4(ap),r0") ;
269}
270
271/* */
272
273a2l(as)
274register char *as ;
275{
276/*
277* Convert null-terminated ascii string to binary
278* and return value.
279* 1st char in string :
280* 0 -> octal
281* x -> hex
282* else decimal
283*/
284register value , base , sign , digit ;
285
286digit = value = sign = 0 ;
287base = 10 ; /* default base */
288
289aloop :
290if ((digit = (*as++)) == 0) return(value) ; /* null */
291
292if (digit == '-') {
293 sign++ ;
294 goto aloop ;
295 }
296
297if (digit == '0') base = 8 ; /* octal base */
298else { if (digit == 'x') base = 16 ; /* hex base */
299 else value = (digit-060) ; /* 060 = '0' */
300 }
301
302while (digit = (*as++)) {
303 if (digit < '0') return(0) ;
304 switch (base) {
305 case 8 : {
306 if (digit > '7') return(0) ;
307 digit -= 060 ;
308 break ;
309 }
310 case 10 : {
311 if (digit > '9') return(0) ;
312 digit -= 060 ;
313 break ;
314 }
315 case 16 : {
316 if (digit <= '9') {
317 digit -= 060 ;
318 break ;
319 }
320 if ((digit >= 'A') && (digit <= 'F')) {
321 digit = (digit - 0101 + 10) ;
322 break ;
323 }
324 if ((digit >= 'a') && (digit <= 'f')) {
325 digit = digit - 0141 + 10 ;
326 break ;
327 }
328 return(0) ;
329 break ;
330 }
331 }
332 value = (value * base) + digit ;
333 }
334return (sign ? -value : value) ;
335}
336
337/* */
338
339taprew()
340{
341/*
342* Function to rewind TM02/TE16 drive
343*/
344TM_cs1->reg = TM_RWND | TM_GO ;
345twait() ;
346if (terror()) return(-1) ;
347return(0) ;
348}
349
350/* */
351
352tapspc(fblk)
353{
354/*
355* Function to space forward 'fblk' blocks on TM02/TE16 drive
356*/
357if (fblk) {
358 TM_fc->reg = (-fblk) ; /* no. blocks */
359 TM_cs1->reg = TM_SFWD | TM_GO ; /* space forward */
360 twait() ;
361 if (terror()) return(-1) ;
362 }
363return(0) ;
364}
365
366/* */
367
368twait()
369{
370/*
371* Function to wait until TM02/TE16 is not busy
372*/
373while ((TM_ds->reg & TM_DRDY) == 0) ;
374}
375
376/* */
377
378terror()
379{
380/*
381* Function to check for TM02 error
382* Return (-1) if error,
383* esle return (0).
384*/
385if (TM_ds->reg & TM_ERR) return(-1) ;
386return(0) ;
387}
388
389/* */
390
391init() {
392/*
393* Initialization.
394* Initialize MBA 0 (disk) and MBA 1 (tape).
395* Initialize TM02/TE16 for drive 0 , 800 BPI, PDP11, etc.
396* Set up MBA 0 and MBA 1 map registers to map a max.
397* transfer of 'BUFSIZ' bytes.
398*/
399register int *mp0 , *mp1 , i , page ;
400
401
402nread = BUFSIZ/blksiz ; /* no. of tape reads to fill input buffer */
403wsize = nread * blksiz ; /* no. bytes each write to disc */
404dblks = wsize/512 ; /* no. of disc blocks on each write */
405RPptr = RP + (dunit * 32 * 4) ; /* start of RP reg's for drive */
406if ((*(RPptr+RP_sr) & RP_MOL) == 0) {
407 putlin("unit not online") ;
408 return(-1) ;
409 }
410
411*(RPptr+RP_cr) = RP_RIP | RP_GO ; /* preset :/
412*(RPptr+RP_off) = RP_FMT ; /* set format bit */
413bytoff = (int)(&input[0])&0777 ; /* byte offset of buffer addr */
414page = ((int)&input[0] >> 9) & 07777777 ; /* start page of buffer */
415mp0 = M0_map ; /* phys addr of MBA 0 map reg base */
416mp1 = M1_map ; /* " " " 1 " " */
417
418i = (((BUFSIZ+511)>>9)&0777) + 1 ; /* max. no. of pages */
419
420while (i--)
421 (*mp0++) = (*mp1++) = 0x80000000 | page++ ; /* map entry */
422
423}
424
425/* */
426
427twrite()
428{
429/*
430* Function to write TM02/TE16 tape drive, 'blksiz' bytes each
431* write, and 'nread' writes.
432*/
433register int i, j ;
434
435j = 0;
436for (i = MIN(nread,count) ; i ; i--) {
437 M1_var->reg = bytoff + j++ * blksiz;
438 M1_bc->reg = (-blksiz) ; /* MBA 1 byte count reg */
439 TM_fc->reg = (-blksiz); /* tape frame counter register */
440 TM_cs1->reg = TM_WRTF | TM_GO ; /* write forward */
441 twait() ; /* wait for ready */
442 if (terror()) return(-1) ; /* return on error */
443 }
444return(0) ; /* normal return */
445}
446
447/* */
448
449dread()
450{
451/*
452* Function to read 'wsize' bytes (512 multiple) from disc
453* to buffer 'input[]".
454*/
455register int i , j ;
456
457*(RPptr+RP_cr) = RP_DC | RP_GO ; /* drive clear */
458*(RPptr+RP_cyl) = dskoff/RP6ST ; /* cylinder no. */
459i = dskoff%RP6ST ;
460j = (i/RP6SEC)<<8 ; /* track */
461*(RPptr+RP_stk) = j | (i%RP6SEC) ; /* sector : track */
462M0_bc->reg = (count<nread?-(count*512):(-wsize)) ; /* byte count */
463M0_var->reg = bytoff ; /* virt addr reg = map no. + byte off */
464*(RPptr+RP_cr) = RP_RD | RP_GO ; /* write */
465
466dskoff =+ dblks ; /* point to next disc sector */
467dwait() ; /* wait for i/o to finish */
468if (derror()) return(-1) ; /* error */
469return(0) ; /* normal return */
470}
471
472/* */
473
474dwait() {
475/*
476* Function to wait MBA 0 RP06 disc unit to be ready.
477*/
478while ((*(RPptr+RP_sr)&RP_DRY) == 0) ;
479}
480
481/* */
482
483derror()
484{
485/*
486* Function to check for MBA 0 RP06 error.
487*/
488if (*(RPptr+RP_sr) & RP_ERR) return(-1) ;
489return(0) ;
490}
491
492/* */
493
494halt()
495{
496asm(" halt") ;
497}
498
499/* */
500
501l2a(val,rptr)
502register int val ;
503register char *rptr ;
504{
505register int i ;
506register char *tp ;
507int knt ;
508char tmp[20] , sign ;
509
510knt = sign = 0 ;
511if (val < 0) {
512 sign++ ;
513 val = (-val) ;
514 }
515
516tp = tmp ;
517loop :
518 knt++ ;
519 i = val/10 ; /* quotient & base 10 */
520 (*tp++) = val%10 + '0' ; /* ascii remainder */
521 val = i ;
522 if (val == 0) {
523 /* done dividing */
524 if (sign) { knt++ ; (*tp++) = '-' ; }
525 for (i = knt ; i ; i--)
526 (*rptr++) = tmp[i-1] ;
527 (*rptr++) = '\0' ;
528 return(knt) ;
529 }
530 else goto loop ;
531}
532
533/* */
534
535echo(lngword)
536register int lngword ;
537{
538char tmp[30] ;
539
540l2a(lngword,tmp) ;
541putlin(tmp) ;
542}